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
i_ilb_socket_set_err(ilb_handle_t h,ilb_status_t err)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
ilb_open(ilb_handle_t * hp)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
ilb_close(ilb_handle_t h)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
i_ilb_do_comm(ilb_handle_t h,ilb_comm_t * ic,size_t ic_sz,ilb_comm_t * rbuf,size_t * rbufsz)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
i_ilb_close_comm(ilb_handle_t h)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