/* $NetBSD: isns_util.c,v 1.2 2012/03/21 05:33:27 matt 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 __RCSID("$NetBSD: isns_util.c,v 1.2 2012/03/21 05:33:27 matt Exp $"); #include #include #include #include #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(void) { 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); } } }