xref: /netbsd-src/lib/libisns/isns_util.c (revision f9113d007ba01ebfad343fed2f314e337ea8c8ce)
1 /*	$NetBSD: isns_util.c,v 1.2 2012/03/21 05:33:27 matt Exp $	*/
2 
3 /*-
4  * Copyright (c) 2004,2009 The NetBSD Foundation, Inc.
5  * All rights reserved.
6  *
7  * This code is derived from software contributed to The NetBSD Foundation
8  * by Wasabi Systems, Inc.
9  *
10  * Redistribution and use in source and binary forms, with or without
11  * modification, are permitted provided that the following conditions
12  * are met:
13  * 1. Redistributions of source code must retain the above copyright
14  *    notice, this list of conditions and the following disclaimer.
15  * 2. Redistributions in binary form must reproduce the above copyright
16  *    notice, this list of conditions and the following disclaimer in the
17  *    documentation and/or other materials provided with the distribution.
18  *
19  * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
20  * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
21  * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
22  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
23  * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
24  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
25  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
26  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
27  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
28  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
29  * POSSIBILITY OF SUCH DAMAGE.
30  */
31 
32 /*
33  * isns_util.c
34  */
35 
36 #include <sys/cdefs.h>
37 __RCSID("$NetBSD: isns_util.c,v 1.2 2012/03/21 05:33:27 matt Exp $");
38 
39 
40 #include <sys/types.h>
41 
42 #include <pthread.h>
43 #include <string.h>
44 #include <unistd.h>
45 
46 #include "isns.h"
47 #include "isns_config.h"
48 
49 #define ISNS_MAX_DISCONNECTS_PER_TRANS	3
50 
51 int
isns_issue_cmd(struct isns_config_s * cfg_p,uint8_t cmd_type)52 isns_issue_cmd(struct isns_config_s *cfg_p, uint8_t cmd_type)
53 {
54 	return (int)write(cfg_p->pipe_fds[1], &cmd_type, 1);
55 }
56 
57 
58 int
isns_issue_cmd_with_data(struct isns_config_s * cfg_p,uint8_t cmd_type,uint8_t * data_p,int data_len)59 isns_issue_cmd_with_data(struct isns_config_s *cfg_p, uint8_t cmd_type,
60     uint8_t *data_p, int data_len)
61 {
62 	struct iovec iov[2];
63 
64 	iov[0].iov_base = &cmd_type;
65 	iov[0].iov_len = 1;
66 	iov[1].iov_base = data_p;
67 	iov[1].iov_len = data_len;
68 
69 	return (int)isns_file_writev(cfg_p->pipe_fds[1], iov, 2);
70 }
71 
72 
73 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)74 isns_change_kevent_list(struct isns_config_s *cfg_p,
75     uintptr_t ident, uint32_t filter, uint32_t flags, int64_t data, intptr_t udata)
76 {
77 	struct kevent evt;
78 
79 	EV_SET(&evt, ident, filter, flags, 0, data, udata);
80 	return kevent(cfg_p->kq, &evt, 1, NULL, 0, NULL);
81 }
82 
83 
84 struct isns_config_s *
isns_new_config(void)85 isns_new_config(void)
86 {
87 	struct isns_config_s *cfg_p;
88 	pthread_mutexattr_t mutexattr;
89 
90 	cfg_p = (struct isns_config_s *)
91 	    isns_malloc(sizeof(struct isns_config_s));
92 	if (cfg_p == NULL) {
93 		DBG("isns_new_config: error on isns_malloc() [1]\n");
94 		return NULL;
95 	}
96 	cfg_p->kq = -1;
97 	cfg_p->pipe_fds[0] = -1;
98 	cfg_p->pipe_fds[1] = -1;
99 	cfg_p->curtask_p = NULL;
100 	cfg_p->sd_connected = 0;
101 	cfg_p->ai_p = NULL;
102 	cfg_p->pdu_in_p = NULL;
103 
104 	cfg_p->refresh_p = NULL;
105 
106 	pthread_mutexattr_init(&mutexattr);
107 	pthread_mutexattr_settype(&mutexattr, ISNS_MUTEX_TYPE_NORMAL);
108 	if (pthread_mutex_init(&cfg_p->taskq_mutex, &mutexattr) != 0) {
109 		DBG("isns_new_config: error on pthread_mutex_init() [1]\n");
110 		isns_free(cfg_p);
111 		return NULL;
112 	}
113 
114 	pthread_mutexattr_init(&mutexattr);
115 	pthread_mutexattr_settype(&mutexattr, ISNS_MUTEX_TYPE_NORMAL);
116 	if (pthread_mutex_init(&cfg_p->trans_mutex, &mutexattr) != 0) {
117 		DBG("isns_new_config: error on pthread_mutex_init() [2]\n");
118 		pthread_mutex_destroy(&cfg_p->taskq_mutex);
119 		isns_free(cfg_p);
120 		return NULL;
121 	}
122 
123 	SIMPLEQ_INIT(&cfg_p->taskq_head);
124 
125 	cfg_p->control_thread_p = (pthread_t *)isns_malloc(sizeof(pthread_t));
126 	if (cfg_p->control_thread_p == NULL) {
127 		DBG("isns_new_config: error on isns_malloc() [1]\n");
128 		isns_destroy_config(cfg_p);
129 		return NULL;
130 	}
131 
132 	return cfg_p;
133 }
134 
135 
136 void
isns_destroy_config(struct isns_config_s * cfg_p)137 isns_destroy_config(struct isns_config_s *cfg_p)
138 {
139 	struct isns_task_s *task_p;
140 
141 	if (cfg_p != NULL) {
142 		if (cfg_p->kq != -1)
143 			close(cfg_p->kq);
144 		if (cfg_p->pipe_fds[0] != -1)
145 			close(cfg_p->pipe_fds[0]);
146 		if (cfg_p->pipe_fds[1] != -1)
147 			close(cfg_p->pipe_fds[1]);
148 		if (cfg_p->control_thread_p != NULL)
149 			isns_free(cfg_p->control_thread_p);
150 		if (cfg_p->refresh_p != NULL) {
151 			if (cfg_p->refresh_p->trans_p != NULL)
152 				isns_free_trans(cfg_p->refresh_p->trans_p);
153 			isns_free(cfg_p->refresh_p);
154 		}
155 		/* Free the current task, if necessary. */
156 		if ((task_p = cfg_p->curtask_p) != NULL) {
157 			if (task_p->task_type == ISNS_TASK_SEND_PDU)
158 				isns_complete_trans(task_p->var.send_pdu.trans_p);
159 			isns_free_task(task_p);
160 		}
161 		/* Empty the task queue of any pending tasks and free them. */
162 		while ((task_p = isns_taskq_remove(cfg_p)) != NULL) {
163 			if (task_p->task_type == ISNS_TASK_SEND_PDU)
164 				isns_complete_trans(task_p->var.send_pdu.trans_p);
165 			isns_free_task(task_p);
166 		}
167 		pthread_mutex_destroy(&cfg_p->taskq_mutex);
168 		pthread_mutex_destroy(&cfg_p->trans_mutex);
169 		if (cfg_p->ai_p != NULL) {
170 			if (cfg_p->ai_p->ai_canonname != NULL)
171 				isns_free(cfg_p->ai_p->ai_canonname);
172 			if (cfg_p->ai_p->ai_addr != NULL)
173 				isns_free(cfg_p->ai_p->ai_addr);
174 			isns_free(cfg_p->ai_p);
175 		}
176 		isns_free(cfg_p);
177 	}
178 }
179 
180 
181 /*
182  * isns_thread_create()
183  */
184 int
isns_thread_create(struct isns_config_s * cfg_p)185 isns_thread_create(struct isns_config_s *cfg_p)
186 {
187 	char namebuf[ISNS_THREAD_MAX_NAMELEN];
188 	int error;
189 	pthread_attr_t attr;
190 
191 	DBG("isns_thread_create: entered\n");
192 
193 	strcpy(namebuf, "isns_control");
194 	error = pthread_attr_init(&attr);
195 	if (error != 0) {
196 		DBG("isns_thread_create: error on pthread_threadattr_init\n");
197 		return error;
198 	}
199 
200 	error = pthread_attr_setname_np(&attr, namebuf, NULL);
201 	if (error != 0) {
202 		DBG("isns_thread_create: "
203 		    "error on pthread_threadattr_setname\n");
204 		pthread_attr_destroy(&attr);
205 		return error;
206 	}
207 
208 	error = pthread_create(cfg_p->control_thread_p,
209 	    &attr, isns_control_thread, cfg_p);
210 	pthread_attr_destroy(&attr);
211 
212 	if (error != 0) {
213 		DBG("isns_thread_create: error on pthread_thread_create\n");
214 		return error;
215     	}
216 
217 	return error;
218 }
219 
220 
221 /*
222  * isns_thread_destroy()
223  */
224 void
isns_thread_destroy(struct isns_config_s * cfg_p)225 isns_thread_destroy(struct isns_config_s *cfg_p)
226 {
227 	int error;
228 	void *rv;
229 
230 	DBG("isns_thread_destroy: entered\n");
231 
232 	if ((cfg_p == NULL) || (cfg_p->control_thread_p == NULL))
233 		return;
234 
235 	DBG("isns_thread_destroy: about to wait (join) on thread\n");
236 	error = pthread_join(*cfg_p->control_thread_p, &rv);
237 	if (error) {
238 		DBG("isns_thread_destroy: error on pthread_thread_join\n");
239 		return;
240 	}
241 
242 	DBG("isns_thread_destroy: done waiting on thread\n");
243 }
244 
245 /*
246  *
247  */
248 void
isns_process_connection_loss(struct isns_config_s * cfg_p)249 isns_process_connection_loss(struct isns_config_s *cfg_p)
250 {
251 	struct isns_trans_s *trans_p;
252 	struct isns_pdu_s *pdu_p, *free_pdu_p;
253 
254 
255 	DBG("isns_process_connection_loss: entered\n");
256 
257 	if (cfg_p->curtask_p != NULL) {
258 		trans_p = cfg_p->curtask_p->var.send_pdu.trans_p;
259 
260 		if (trans_p->disconnect_cnt == ISNS_MAX_DISCONNECTS_PER_TRANS) {
261 			isns_complete_trans(trans_p);
262 			isns_end_task(cfg_p->curtask_p);
263 
264 			if (cfg_p->pdu_in_p != NULL) {
265 				isns_free_pdu(cfg_p->pdu_in_p);
266 				cfg_p->pdu_in_p = NULL;
267 			}
268 		} else {
269 			trans_p->disconnect_cnt++;
270 
271 			if (trans_p->pdu_rsp_list != NULL) {
272 				pdu_p = trans_p->pdu_rsp_list;
273 				while (pdu_p != NULL) {
274 					free_pdu_p = pdu_p;
275 					pdu_p = pdu_p->next;
276 					isns_free_pdu(free_pdu_p);
277 				}
278 			}
279 
280 			isns_taskq_insert_head(cfg_p, cfg_p->curtask_p);
281 			cfg_p->curtask_p = NULL;
282 
283 			isns_issue_cmd(cfg_p, ISNS_CMD_PROCESS_TASKQ);
284 		}
285 	}
286 }
287