xref: /titanic_52/usr/src/lib/libilb/common/ilb_comm.c (revision dbed73cbda2229fd1aa6dc5743993cae7f0a7ee9)
1*dbed73cbSSangeeta Misra /*
2*dbed73cbSSangeeta Misra  * CDDL HEADER START
3*dbed73cbSSangeeta Misra  *
4*dbed73cbSSangeeta Misra  * The contents of this file are subject to the terms of the
5*dbed73cbSSangeeta Misra  * Common Development and Distribution License (the "License").
6*dbed73cbSSangeeta Misra  * You may not use this file except in compliance with the License.
7*dbed73cbSSangeeta Misra  *
8*dbed73cbSSangeeta Misra  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9*dbed73cbSSangeeta Misra  * or http://www.opensolaris.org/os/licensing.
10*dbed73cbSSangeeta Misra  * See the License for the specific language governing permissions
11*dbed73cbSSangeeta Misra  * and limitations under the License.
12*dbed73cbSSangeeta Misra  *
13*dbed73cbSSangeeta Misra  * When distributing Covered Code, include this CDDL HEADER in each
14*dbed73cbSSangeeta Misra  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15*dbed73cbSSangeeta Misra  * If applicable, add the following below this CDDL HEADER, with the
16*dbed73cbSSangeeta Misra  * fields enclosed by brackets "[]" replaced with your own identifying
17*dbed73cbSSangeeta Misra  * information: Portions Copyright [yyyy] [name of copyright owner]
18*dbed73cbSSangeeta Misra  *
19*dbed73cbSSangeeta Misra  * CDDL HEADER END
20*dbed73cbSSangeeta Misra  */
21*dbed73cbSSangeeta Misra 
22*dbed73cbSSangeeta Misra /*
23*dbed73cbSSangeeta Misra  * Copyright 2009 Sun Microsystems, Inc.  All rights reserved.
24*dbed73cbSSangeeta Misra  * Use is subject to license terms.
25*dbed73cbSSangeeta Misra  */
26*dbed73cbSSangeeta Misra 
27*dbed73cbSSangeeta Misra #include <stdlib.h>
28*dbed73cbSSangeeta Misra #include <strings.h>
29*dbed73cbSSangeeta Misra #include <unistd.h>
30*dbed73cbSSangeeta Misra #include <stddef.h>
31*dbed73cbSSangeeta Misra #include <assert.h>
32*dbed73cbSSangeeta Misra #include <sys/types.h>
33*dbed73cbSSangeeta Misra #include <sys/socket.h>
34*dbed73cbSSangeeta Misra #include <thread.h>
35*dbed73cbSSangeeta Misra #include <synch.h>
36*dbed73cbSSangeeta Misra #include <libilb_impl.h>
37*dbed73cbSSangeeta Misra #include <libilb.h>
38*dbed73cbSSangeeta Misra 
39*dbed73cbSSangeeta Misra /* Assertion: the calling thread has a hold on the handle */
40*dbed73cbSSangeeta Misra static void
41*dbed73cbSSangeeta Misra i_ilb_socket_set_err(ilb_handle_t h, ilb_status_t err)
42*dbed73cbSSangeeta Misra {
43*dbed73cbSSangeeta Misra 	ilb_handle_impl_t	*hi = (ilb_handle_impl_t *)h;
44*dbed73cbSSangeeta Misra 
45*dbed73cbSSangeeta Misra 	if (h == ILB_INVALID_HANDLE)
46*dbed73cbSSangeeta Misra 		return;
47*dbed73cbSSangeeta Misra 	hi->h_valid = B_FALSE;
48*dbed73cbSSangeeta Misra 	hi->h_error = err;
49*dbed73cbSSangeeta Misra }
50*dbed73cbSSangeeta Misra 
51*dbed73cbSSangeeta Misra ilb_status_t
52*dbed73cbSSangeeta Misra ilb_open(ilb_handle_t *hp)
53*dbed73cbSSangeeta Misra {
54*dbed73cbSSangeeta Misra 	ilb_handle_impl_t	*hi = NULL;
55*dbed73cbSSangeeta Misra 	int			s = -1;
56*dbed73cbSSangeeta Misra 	struct sockaddr_un sa = {AF_UNIX, SOCKET_PATH};
57*dbed73cbSSangeeta Misra 	ilb_status_t		rc = ILB_STATUS_OK;
58*dbed73cbSSangeeta Misra 	int			sobufsz;
59*dbed73cbSSangeeta Misra 
60*dbed73cbSSangeeta Misra 	if (hp == NULL)
61*dbed73cbSSangeeta Misra 		return (ILB_STATUS_EINVAL);
62*dbed73cbSSangeeta Misra 
63*dbed73cbSSangeeta Misra 	hi = calloc(sizeof (*hi), 1);
64*dbed73cbSSangeeta Misra 	if (hi == NULL)
65*dbed73cbSSangeeta Misra 		return (ILB_STATUS_ENOMEM);
66*dbed73cbSSangeeta Misra 
67*dbed73cbSSangeeta Misra 	if (cond_init(&hi->h_cv, USYNC_THREAD, NULL) != 0) {
68*dbed73cbSSangeeta Misra 		rc = ILB_STATUS_INTERNAL;
69*dbed73cbSSangeeta Misra 		goto out;
70*dbed73cbSSangeeta Misra 	}
71*dbed73cbSSangeeta Misra 
72*dbed73cbSSangeeta Misra 	if (mutex_init(&hi->h_lock, USYNC_THREAD | LOCK_ERRORCHECK, NULL)
73*dbed73cbSSangeeta Misra 	    != 0) {
74*dbed73cbSSangeeta Misra 		rc = ILB_STATUS_INTERNAL;
75*dbed73cbSSangeeta Misra 		goto out;
76*dbed73cbSSangeeta Misra 	}
77*dbed73cbSSangeeta Misra 
78*dbed73cbSSangeeta Misra 	hi->h_busy = B_FALSE;
79*dbed73cbSSangeeta Misra 
80*dbed73cbSSangeeta Misra 	if ((s = socket(PF_UNIX, SOCK_SEQPACKET, 0)) == -1 ||
81*dbed73cbSSangeeta Misra 	    connect(s, (struct sockaddr *)&sa, sizeof (sa.sun_path))
82*dbed73cbSSangeeta Misra 	    == -1) {
83*dbed73cbSSangeeta Misra 		rc = ILB_STATUS_SOCKET;
84*dbed73cbSSangeeta Misra 		goto out;
85*dbed73cbSSangeeta Misra 	}
86*dbed73cbSSangeeta Misra 
87*dbed73cbSSangeeta Misra 	/* The socket buffer must be at least the max size of a message */
88*dbed73cbSSangeeta Misra 	sobufsz = ILBD_MSG_SIZE;
89*dbed73cbSSangeeta Misra 	if (setsockopt(s, SOL_SOCKET, SO_SNDBUF, &sobufsz,
90*dbed73cbSSangeeta Misra 	    sizeof (sobufsz)) != 0) {
91*dbed73cbSSangeeta Misra 		rc = ILB_STATUS_SOCKET;
92*dbed73cbSSangeeta Misra 		(void) close(s);
93*dbed73cbSSangeeta Misra 		goto out;
94*dbed73cbSSangeeta Misra 	}
95*dbed73cbSSangeeta Misra 	if (setsockopt(s, SOL_SOCKET, SO_RCVBUF, &sobufsz,
96*dbed73cbSSangeeta Misra 	    sizeof (sobufsz)) != 0) {
97*dbed73cbSSangeeta Misra 		rc = ILB_STATUS_SOCKET;
98*dbed73cbSSangeeta Misra 		(void) close(s);
99*dbed73cbSSangeeta Misra 		goto out;
100*dbed73cbSSangeeta Misra 	}
101*dbed73cbSSangeeta Misra 
102*dbed73cbSSangeeta Misra 	hi->h_socket = s;
103*dbed73cbSSangeeta Misra 	hi->h_valid = B_TRUE;
104*dbed73cbSSangeeta Misra 
105*dbed73cbSSangeeta Misra out:
106*dbed73cbSSangeeta Misra 	if (rc != ILB_STATUS_OK && s != -1)
107*dbed73cbSSangeeta Misra 		(void) close(s);
108*dbed73cbSSangeeta Misra 
109*dbed73cbSSangeeta Misra 	if (rc == ILB_STATUS_OK) {
110*dbed73cbSSangeeta Misra 		*hp = (ilb_handle_t)hi;
111*dbed73cbSSangeeta Misra 	} else {
112*dbed73cbSSangeeta Misra 		free(hi);
113*dbed73cbSSangeeta Misra 		*hp = ILB_INVALID_HANDLE;
114*dbed73cbSSangeeta Misra 	}
115*dbed73cbSSangeeta Misra 	return (rc);
116*dbed73cbSSangeeta Misra }
117*dbed73cbSSangeeta Misra 
118*dbed73cbSSangeeta Misra ilb_status_t
119*dbed73cbSSangeeta Misra ilb_close(ilb_handle_t h)
120*dbed73cbSSangeeta Misra {
121*dbed73cbSSangeeta Misra 	ilb_handle_impl_t	*hi = (ilb_handle_impl_t *)h;
122*dbed73cbSSangeeta Misra 
123*dbed73cbSSangeeta Misra 	if (h == ILB_INVALID_HANDLE)
124*dbed73cbSSangeeta Misra 		return (ILB_STATUS_EINVAL);
125*dbed73cbSSangeeta Misra 
126*dbed73cbSSangeeta Misra 	if (mutex_lock(&hi->h_lock) != 0)
127*dbed73cbSSangeeta Misra 		return (ILB_STATUS_INTERNAL);
128*dbed73cbSSangeeta Misra 
129*dbed73cbSSangeeta Misra 	/* Somebody has done a close, no need to do anything. */
130*dbed73cbSSangeeta Misra 	if (hi->h_closing) {
131*dbed73cbSSangeeta Misra 		return (ILB_STATUS_OK);
132*dbed73cbSSangeeta Misra 	} else {
133*dbed73cbSSangeeta Misra 		hi->h_closing = B_TRUE;
134*dbed73cbSSangeeta Misra 		hi->h_error = ILB_STATUS_HANDLE_CLOSING;
135*dbed73cbSSangeeta Misra 	}
136*dbed73cbSSangeeta Misra 
137*dbed73cbSSangeeta Misra 	/* Wait until there is nobody waiting. */
138*dbed73cbSSangeeta Misra 	while (hi->h_waiter > 0) {
139*dbed73cbSSangeeta Misra 		if (cond_wait(&hi->h_cv, &hi->h_lock) != 0) {
140*dbed73cbSSangeeta Misra 			(void) mutex_unlock(&hi->h_lock);
141*dbed73cbSSangeeta Misra 			return (ILB_STATUS_INTERNAL);
142*dbed73cbSSangeeta Misra 		}
143*dbed73cbSSangeeta Misra 	}
144*dbed73cbSSangeeta Misra 	/* No one is waiting, proceed to free the handle. */
145*dbed73cbSSangeeta Misra 
146*dbed73cbSSangeeta Misra 	(void) close(hi->h_socket);
147*dbed73cbSSangeeta Misra 	(void) mutex_destroy(&hi->h_lock);
148*dbed73cbSSangeeta Misra 	(void) cond_destroy(&hi->h_cv);
149*dbed73cbSSangeeta Misra 	free(hi);
150*dbed73cbSSangeeta Misra 	return (ILB_STATUS_OK);
151*dbed73cbSSangeeta Misra }
152*dbed73cbSSangeeta Misra 
153*dbed73cbSSangeeta Misra /*
154*dbed73cbSSangeeta Misra  * Unified routine to communicate with ilbd.
155*dbed73cbSSangeeta Misra  *
156*dbed73cbSSangeeta Misra  * If ic is non-NULL, it means that the caller wants to send something
157*dbed73cbSSangeeta Misra  * to ilbd and expects a reply.  If ic is NULL, it means that the caller
158*dbed73cbSSangeeta Misra  * only expects to receive from ilbd.
159*dbed73cbSSangeeta Misra  *
160*dbed73cbSSangeeta Misra  * The rbuf is the buffer supplied by the caller for receiving.  If it
161*dbed73cbSSangeeta Misra  * is NULL, it means that there is no reply expected.
162*dbed73cbSSangeeta Misra  *
163*dbed73cbSSangeeta Misra  * This function will not close() the socket to kernel unless there is
164*dbed73cbSSangeeta Misra  * an error.  If the transaction only consists of one exchange, the caller
165*dbed73cbSSangeeta Misra  * can use i_ilb_close_comm() to close() the socket when done.
166*dbed73cbSSangeeta Misra  */
167*dbed73cbSSangeeta Misra ilb_status_t
168*dbed73cbSSangeeta Misra i_ilb_do_comm(ilb_handle_t h, ilb_comm_t *ic, size_t ic_sz, ilb_comm_t *rbuf,
169*dbed73cbSSangeeta Misra     size_t *rbufsz)
170*dbed73cbSSangeeta Misra {
171*dbed73cbSSangeeta Misra 	ilb_status_t		rc = ILB_STATUS_OK;
172*dbed73cbSSangeeta Misra 	int			r, s;
173*dbed73cbSSangeeta Misra 	ilb_handle_impl_t	*hi = (ilb_handle_impl_t *)h;
174*dbed73cbSSangeeta Misra 
175*dbed73cbSSangeeta Misra 	assert(rbuf != NULL);
176*dbed73cbSSangeeta Misra 	if (h == ILB_INVALID_HANDLE)
177*dbed73cbSSangeeta Misra 		return (ILB_STATUS_EINVAL);
178*dbed73cbSSangeeta Misra 
179*dbed73cbSSangeeta Misra 	if (mutex_lock(&hi->h_lock) != 0)
180*dbed73cbSSangeeta Misra 		return (ILB_STATUS_INTERNAL);
181*dbed73cbSSangeeta Misra 
182*dbed73cbSSangeeta Misra 	hi->h_waiter++;
183*dbed73cbSSangeeta Misra 	while (hi->h_busy) {
184*dbed73cbSSangeeta Misra 		if (cond_wait(&hi->h_cv, &hi->h_lock) != 0) {
185*dbed73cbSSangeeta Misra 			hi->h_waiter--;
186*dbed73cbSSangeeta Misra 			(void) cond_signal(&hi->h_cv);
187*dbed73cbSSangeeta Misra 			(void) mutex_unlock(&hi->h_lock);
188*dbed73cbSSangeeta Misra 			return (ILB_STATUS_INTERNAL);
189*dbed73cbSSangeeta Misra 		}
190*dbed73cbSSangeeta Misra 	}
191*dbed73cbSSangeeta Misra 
192*dbed73cbSSangeeta Misra 	if (!hi->h_valid || hi->h_closing) {
193*dbed73cbSSangeeta Misra 		hi->h_waiter--;
194*dbed73cbSSangeeta Misra 		(void) cond_signal(&hi->h_cv);
195*dbed73cbSSangeeta Misra 		(void) mutex_unlock(&hi->h_lock);
196*dbed73cbSSangeeta Misra 		return (hi->h_error);
197*dbed73cbSSangeeta Misra 	}
198*dbed73cbSSangeeta Misra 
199*dbed73cbSSangeeta Misra 	hi->h_busy = B_TRUE;
200*dbed73cbSSangeeta Misra 	(void) mutex_unlock(&hi->h_lock);
201*dbed73cbSSangeeta Misra 
202*dbed73cbSSangeeta Misra 	s = hi->h_socket;
203*dbed73cbSSangeeta Misra 
204*dbed73cbSSangeeta Misra 	r = send(s, ic, ic_sz, 0);
205*dbed73cbSSangeeta Misra 	if (r < ic_sz) {
206*dbed73cbSSangeeta Misra 		rc = ILB_STATUS_WRITE;
207*dbed73cbSSangeeta Misra 		goto socket_error;
208*dbed73cbSSangeeta Misra 	}
209*dbed73cbSSangeeta Misra 	rc = ILB_STATUS_OK;
210*dbed73cbSSangeeta Misra 
211*dbed73cbSSangeeta Misra 	if ((r = recv(s, rbuf, *rbufsz, 0)) <= 0) {
212*dbed73cbSSangeeta Misra 		rc = ILB_STATUS_READ;
213*dbed73cbSSangeeta Misra 	} else {
214*dbed73cbSSangeeta Misra 		*rbufsz = r;
215*dbed73cbSSangeeta Misra 		goto out;
216*dbed73cbSSangeeta Misra 	}
217*dbed73cbSSangeeta Misra 
218*dbed73cbSSangeeta Misra socket_error:
219*dbed73cbSSangeeta Misra 	i_ilb_socket_set_err(h, rc);
220*dbed73cbSSangeeta Misra 
221*dbed73cbSSangeeta Misra out:
222*dbed73cbSSangeeta Misra 	(void) mutex_lock(&hi->h_lock);
223*dbed73cbSSangeeta Misra 	hi->h_busy = B_FALSE;
224*dbed73cbSSangeeta Misra 	hi->h_waiter--;
225*dbed73cbSSangeeta Misra 	(void) cond_signal(&hi->h_cv);
226*dbed73cbSSangeeta Misra 	(void) mutex_unlock(&hi->h_lock);
227*dbed73cbSSangeeta Misra 
228*dbed73cbSSangeeta Misra 	return (rc);
229*dbed73cbSSangeeta Misra }
230*dbed73cbSSangeeta Misra 
231*dbed73cbSSangeeta Misra void
232*dbed73cbSSangeeta Misra i_ilb_close_comm(ilb_handle_t h)
233*dbed73cbSSangeeta Misra {
234*dbed73cbSSangeeta Misra 	(void) ilb_close(h);
235*dbed73cbSSangeeta Misra }
236