NetBSD/lib/libisns/isns_util.c
agc dc2ecebec9 Initial import of libisns, contributed to the NetBSD Foundation by
Wasabi Systems, Inc.

libisns(3) is an implementation of the iSNS protocol as defined in
IETF RFC 4171, exporting an API that simplifies Internet Storage Name
Service (iSNS) client implementations.
2011-01-16 01:22:50 +00:00

287 lines
7.3 KiB
C

/* $NetBSD: isns_util.c,v 1.1.1.1 2011/01/16 01:22:50 agc Exp $ */
/*-
* Copyright (c) 2004,2009 The NetBSD Foundation, Inc.
* All rights reserved.
*
* This code is derived from software contributed to The NetBSD Foundation
* by Wasabi Systems, Inc.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
* ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
* TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
* PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
* BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*/
/*
* isns_util.c
*/
#include <sys/cdefs.h>
__RCSID("$NetBSD: isns_util.c,v 1.1.1.1 2011/01/16 01:22:50 agc Exp $");
#include <sys/types.h>
#include <pthread.h>
#include <string.h>
#include <unistd.h>
#include "isns.h"
#include "isns_config.h"
#define ISNS_MAX_DISCONNECTS_PER_TRANS 3
int
isns_issue_cmd(struct isns_config_s *cfg_p, uint8_t cmd_type)
{
return (int)write(cfg_p->pipe_fds[1], &cmd_type, 1);
}
int
isns_issue_cmd_with_data(struct isns_config_s *cfg_p, uint8_t cmd_type,
uint8_t *data_p, int data_len)
{
struct iovec iov[2];
iov[0].iov_base = &cmd_type;
iov[0].iov_len = 1;
iov[1].iov_base = data_p;
iov[1].iov_len = data_len;
return (int)isns_file_writev(cfg_p->pipe_fds[1], iov, 2);
}
int
isns_change_kevent_list(struct isns_config_s *cfg_p,
uintptr_t ident, uint32_t filter, uint32_t flags, int64_t data, intptr_t udata)
{
struct kevent evt;
EV_SET(&evt, ident, filter, flags, 0, data, udata);
return kevent(cfg_p->kq, &evt, 1, NULL, 0, NULL);
}
struct isns_config_s *
isns_new_config()
{
struct isns_config_s *cfg_p;
pthread_mutexattr_t mutexattr;
cfg_p = (struct isns_config_s *)
isns_malloc(sizeof(struct isns_config_s));
if (cfg_p == NULL) {
DBG("isns_new_config: error on isns_malloc() [1]\n");
return NULL;
}
cfg_p->kq = -1;
cfg_p->pipe_fds[0] = -1;
cfg_p->pipe_fds[1] = -1;
cfg_p->curtask_p = NULL;
cfg_p->sd_connected = 0;
cfg_p->ai_p = NULL;
cfg_p->pdu_in_p = NULL;
cfg_p->refresh_p = NULL;
pthread_mutexattr_init(&mutexattr);
pthread_mutexattr_settype(&mutexattr, ISNS_MUTEX_TYPE_NORMAL);
if (pthread_mutex_init(&cfg_p->taskq_mutex, &mutexattr) != 0) {
DBG("isns_new_config: error on pthread_mutex_init() [1]\n");
isns_free(cfg_p);
return NULL;
}
pthread_mutexattr_init(&mutexattr);
pthread_mutexattr_settype(&mutexattr, ISNS_MUTEX_TYPE_NORMAL);
if (pthread_mutex_init(&cfg_p->trans_mutex, &mutexattr) != 0) {
DBG("isns_new_config: error on pthread_mutex_init() [2]\n");
pthread_mutex_destroy(&cfg_p->taskq_mutex);
isns_free(cfg_p);
return NULL;
}
SIMPLEQ_INIT(&cfg_p->taskq_head);
cfg_p->control_thread_p = (pthread_t *)isns_malloc(sizeof(pthread_t));
if (cfg_p->control_thread_p == NULL) {
DBG("isns_new_config: error on isns_malloc() [1]\n");
isns_destroy_config(cfg_p);
return NULL;
}
return cfg_p;
}
void
isns_destroy_config(struct isns_config_s *cfg_p)
{
struct isns_task_s *task_p;
if (cfg_p != NULL) {
if (cfg_p->kq != -1)
close(cfg_p->kq);
if (cfg_p->pipe_fds[0] != -1)
close(cfg_p->pipe_fds[0]);
if (cfg_p->pipe_fds[1] != -1)
close(cfg_p->pipe_fds[1]);
if (cfg_p->control_thread_p != NULL)
isns_free(cfg_p->control_thread_p);
if (cfg_p->refresh_p != NULL) {
if (cfg_p->refresh_p->trans_p != NULL)
isns_free_trans(cfg_p->refresh_p->trans_p);
isns_free(cfg_p->refresh_p);
}
/* Free the current task, if necessary. */
if ((task_p = cfg_p->curtask_p) != NULL) {
if (task_p->task_type == ISNS_TASK_SEND_PDU)
isns_complete_trans(task_p->var.send_pdu.trans_p);
isns_free_task(task_p);
}
/* Empty the task queue of any pending tasks and free them. */
while ((task_p = isns_taskq_remove(cfg_p)) != NULL) {
if (task_p->task_type == ISNS_TASK_SEND_PDU)
isns_complete_trans(task_p->var.send_pdu.trans_p);
isns_free_task(task_p);
}
pthread_mutex_destroy(&cfg_p->taskq_mutex);
pthread_mutex_destroy(&cfg_p->trans_mutex);
if (cfg_p->ai_p != NULL) {
if (cfg_p->ai_p->ai_canonname != NULL)
isns_free(cfg_p->ai_p->ai_canonname);
if (cfg_p->ai_p->ai_addr != NULL)
isns_free(cfg_p->ai_p->ai_addr);
isns_free(cfg_p->ai_p);
}
isns_free(cfg_p);
}
}
/*
* isns_thread_create()
*/
int
isns_thread_create(struct isns_config_s *cfg_p)
{
char namebuf[ISNS_THREAD_MAX_NAMELEN];
int error;
pthread_attr_t attr;
DBG("isns_thread_create: entered\n");
strcpy(namebuf, "isns_control");
error = pthread_attr_init(&attr);
if (error != 0) {
DBG("isns_thread_create: error on pthread_threadattr_init\n");
return error;
}
error = pthread_attr_setname_np(&attr, namebuf, NULL);
if (error != 0) {
DBG("isns_thread_create: "
"error on pthread_threadattr_setname\n");
pthread_attr_destroy(&attr);
return error;
}
error = pthread_create(cfg_p->control_thread_p,
&attr, isns_control_thread, cfg_p);
pthread_attr_destroy(&attr);
if (error != 0) {
DBG("isns_thread_create: error on pthread_thread_create\n");
return error;
}
return error;
}
/*
* isns_thread_destroy()
*/
void
isns_thread_destroy(struct isns_config_s *cfg_p)
{
int error;
void *rv;
DBG("isns_thread_destroy: entered\n");
if ((cfg_p == NULL) || (cfg_p->control_thread_p == NULL))
return;
DBG("isns_thread_destroy: about to wait (join) on thread\n");
error = pthread_join(*cfg_p->control_thread_p, &rv);
if (error) {
DBG("isns_thread_destroy: error on pthread_thread_join\n");
return;
}
DBG("isns_thread_destroy: done waiting on thread\n");
}
/*
*
*/
void
isns_process_connection_loss(struct isns_config_s *cfg_p)
{
struct isns_trans_s *trans_p;
struct isns_pdu_s *pdu_p, *free_pdu_p;
DBG("isns_process_connection_loss: entered\n");
if (cfg_p->curtask_p != NULL) {
trans_p = cfg_p->curtask_p->var.send_pdu.trans_p;
if (trans_p->disconnect_cnt == ISNS_MAX_DISCONNECTS_PER_TRANS) {
isns_complete_trans(trans_p);
isns_end_task(cfg_p->curtask_p);
if (cfg_p->pdu_in_p != NULL) {
isns_free_pdu(cfg_p->pdu_in_p);
cfg_p->pdu_in_p = NULL;
}
} else {
trans_p->disconnect_cnt++;
if (trans_p->pdu_rsp_list != NULL) {
pdu_p = trans_p->pdu_rsp_list;
while (pdu_p != NULL) {
free_pdu_p = pdu_p;
pdu_p = pdu_p->next;
isns_free_pdu(free_pdu_p);
}
}
isns_taskq_insert_head(cfg_p, cfg_p->curtask_p);
cfg_p->curtask_p = NULL;
isns_issue_cmd(cfg_p, ISNS_CMD_PROCESS_TASKQ);
}
}
}