xref: /titanic_44/usr/src/lib/smbsrv/libmlsvc/common/mlsvc_client.c (revision 3c4993fb5a74112f361d71dab20997bdc749a7fb)
1 /*
2  * CDDL HEADER START
3  *
4  * The contents of this file are subject to the terms of the
5  * Common Development and Distribution License (the "License").
6  * You may not use this file except in compliance with the License.
7  *
8  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9  * or http://www.opensolaris.org/os/licensing.
10  * See the License for the specific language governing permissions
11  * and limitations under the License.
12  *
13  * When distributing Covered Code, include this CDDL HEADER in each
14  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15  * If applicable, add the following below this CDDL HEADER, with the
16  * fields enclosed by brackets "[]" replaced with your own identifying
17  * information: Portions Copyright [yyyy] [name of copyright owner]
18  *
19  * CDDL HEADER END
20  */
21 /*
22  * Copyright 2007 Sun Microsystems, Inc.  All rights reserved.
23  * Use is subject to license terms.
24  */
25 
26 #pragma ident	"%Z%%M%	%I%	%E% SMI"
27 
28 /*
29  * Context functions to support the RPC interface library.
30  */
31 
32 #include <sys/errno.h>
33 #include <strings.h>
34 
35 #include <smbsrv/libsmb.h>
36 #include <smbsrv/libsmbrdr.h>
37 #include <smbsrv/mlsvc_util.h>
38 
39 static int mlsvc_xa_init(struct mlrpc_client *, struct mlrpc_xaction *,
40     mlrpc_heap_t *);
41 static int mlsvc_xa_exchange(struct mlrpc_client *, struct mlrpc_xaction *);
42 static int mlsvc_xa_read(struct mlrpc_client *, struct mlrpc_xaction *);
43 static int mlsvc_xa_preserve(struct mlrpc_client *, struct mlrpc_xaction *,
44     mlrpc_heapref_t *);
45 static int mlsvc_xa_destruct(struct mlrpc_client *, struct mlrpc_xaction *);
46 static void mlsvc_xa_release(struct mlrpc_client *, mlrpc_heapref_t *heapref);
47 
48 /*
49  * mlsvc_rpc_bind
50  *
51  * This the entry point for all client RPC services. This call must be
52  * made to initialize an RPC context structure and bind to the remote
53  * service before any RPCs can be exchanged with that service. The
54  * descriptor is a wrapper that is used to associate an RPC handle with
55  * the context data for that specific instance of the interface. The
56  * handle is zeroed to ensure that it doesn't look like a valid handle.
57  * The context handle is assigned to point at the RPC handle so that we
58  * know when to free the context. As each handle is initialized it will
59  * include a pointer to this context but only when we close this initial
60  * RPC handle can the context be freed.
61  *
62  * On success, return a pointer to the descriptor. Otherwise return a
63  * null pointer.
64  */
65 int
66 mlsvc_rpc_bind(mlsvc_handle_t *desc, int fid, char *service)
67 {
68 	struct mlsvc_rpc_context *context;
69 	int rc;
70 
71 	bzero(&desc->handle, sizeof (ms_handle_t));
72 
73 	context = malloc(sizeof (struct mlsvc_rpc_context));
74 	if ((desc->context = context) == NULL)
75 		return (-1);
76 
77 	bzero(context, sizeof (struct mlsvc_rpc_context));
78 	context->cli.context = context;
79 
80 	mlrpc_binding_pool_initialize(&context->cli.binding_list,
81 	    context->binding_pool, CTXT_N_BINDING_POOL);
82 
83 	context->fid = fid;
84 	context->handle = &desc->handle;
85 	context->cli.xa_init = mlsvc_xa_init;
86 	context->cli.xa_exchange = mlsvc_xa_exchange;
87 	context->cli.xa_read = mlsvc_xa_read;
88 	context->cli.xa_preserve = mlsvc_xa_preserve;
89 	context->cli.xa_destruct = mlsvc_xa_destruct;
90 	context->cli.xa_release = mlsvc_xa_release;
91 
92 	rc = mlrpc_c_bind(&context->cli, service, &context->binding);
93 	if (MLRPC_DRC_IS_FAULT(rc)) {
94 		free(context);
95 		desc->context = NULL;
96 		return (-1);
97 	}
98 
99 	return (rc);
100 }
101 
102 /*
103  * mlsvc_rpc_init
104  *
105  * This function must be called by client side applications before
106  * calling mlsvc_rpc_call to allocate a heap. The heap must be
107  * destroyed by either calling mlrpc_heap_destroy or mlsvc_rpc_free.
108  * Use mlrpc_heap_destroy if mlsvc_rpc_call has not yet been called.
109  * Otherwise use mlsvc_rpc_free.
110  *
111  * Returns 0 on success. Otherwise returns -1 to indicate an error.
112  */
113 int
114 mlsvc_rpc_init(mlrpc_heapref_t *heapref)
115 {
116 	bzero(heapref, sizeof (mlrpc_heapref_t));
117 
118 	if ((heapref->heap = mlrpc_heap_create()) == NULL)
119 		return (-1);
120 
121 	return (0);
122 }
123 
124 /*
125  * mlsvc_rpc_call
126  *
127  * This function should be called by the client RPC interface functions
128  * to make an RPC call. The remote service is identified by the context
129  * handle, which should have been initialized with by mlsvc_rpc_bind.
130  */
131 int
132 mlsvc_rpc_call(struct mlsvc_rpc_context *context, int opnum, void *params,
133     mlrpc_heapref_t *heapref)
134 {
135 	return (mlrpc_c_call(context->binding, opnum, params, heapref));
136 }
137 
138 /*
139  * mlsvc_rpc_free
140  *
141  * This function should be called by the client RPC interface functions
142  * to free the heap after an RPC call returns.
143  */
144 void
145 mlsvc_rpc_free(struct mlsvc_rpc_context *context, mlrpc_heapref_t *heapref)
146 {
147 	mlrpc_c_free_heap(context->binding, heapref);
148 }
149 
150 /*
151  * The following functions provide the callback interface in the
152  * context handle.
153  */
154 /*ARGSUSED*/
155 static int
156 mlsvc_xa_init(struct mlrpc_client *mcli, struct mlrpc_xaction *mxa,
157     mlrpc_heap_t *heap)
158 {
159 	struct mlndr_stream *recv_mlnds = &mxa->recv_mlnds;
160 	struct mlndr_stream *send_mlnds = &mxa->send_mlnds;
161 
162 	/*
163 	 * If the caller hasn't provided a heap, create one here.
164 	 */
165 	if (heap == 0) {
166 		if ((heap = mlrpc_heap_create()) == 0)
167 			return (-1);
168 	}
169 
170 	mxa->heap = heap;
171 
172 	mlnds_initialize(send_mlnds, 0, NDR_MODE_CALL_SEND, heap);
173 	mlnds_initialize(recv_mlnds, 16 * 1024, NDR_MODE_RETURN_RECV, heap);
174 	return (0);
175 }
176 
177 /*
178  * mlsvc_xa_exchange
179  *
180  * This is the entry pointy for an RPC client call exchange with
181  * a server, which will result in an smbrdr SmbTransact request.
182  *
183  * SmbTransact should return the number of bytes received, which
184  * we record as the PDU size, or a negative error code.
185  */
186 static int
187 mlsvc_xa_exchange(struct mlrpc_client *mcli, struct mlrpc_xaction *mxa)
188 {
189 	struct mlsvc_rpc_context *context = mcli->context;
190 	struct mlndr_stream *recv_mlnds = &mxa->recv_mlnds;
191 	struct mlndr_stream *send_mlnds = &mxa->send_mlnds;
192 	int rc;
193 
194 	rc = smbrdr_rpc_transact(context->fid,
195 	    (char *)send_mlnds->pdu_base_offset, send_mlnds->pdu_size,
196 	    (char *)recv_mlnds->pdu_base_offset, recv_mlnds->pdu_max_size);
197 
198 	if (rc < 0)
199 		recv_mlnds->pdu_size = 0;
200 	else
201 		recv_mlnds->pdu_size = rc;
202 
203 	return (rc);
204 }
205 
206 /*
207  * mlsvc_xa_read
208  *
209  * This entry point will be invoked if the xa-exchange response contained
210  * only the first fragment of a multi-fragment response.  The RPC client
211  * code will then make repeated xa-read requests to obtain the remaining
212  * fragments, which will result in smbrdr SmbReadX requests.
213  *
214  * SmbReadX should return the number of bytes received, in which case we
215  * expand the PDU size to include the received data, or a negative error
216  * code.
217  */
218 static int
219 mlsvc_xa_read(struct mlrpc_client *mcli, struct mlrpc_xaction *mxa)
220 {
221 	struct mlsvc_rpc_context *context = mcli->context;
222 	struct mlndr_stream *mlnds = &mxa->recv_mlnds;
223 	int len;
224 	int rc;
225 
226 	if ((len = (mlnds->pdu_max_size - mlnds->pdu_size)) < 0)
227 		return (-1);
228 
229 	rc = smbrdr_rpc_readx(context->fid,
230 	    (char *)mlnds->pdu_base_offset + mlnds->pdu_size, len);
231 
232 	if (rc < 0)
233 		return (-1);
234 
235 	mlnds->pdu_size += rc;
236 
237 	if (mlnds->pdu_size > mlnds->pdu_max_size) {
238 		mlnds->pdu_size = mlnds->pdu_max_size;
239 		return (-1);
240 	}
241 
242 	return (rc);
243 }
244 
245 /*
246  * mlsvc_xa_preserve
247  *
248  * This function is called to preserve the heap. We save a reference
249  * to the heap and set the mxa heap pointer to null so that the heap
250  * will not be discarded when mlsvc_xa_destruct is called.
251  */
252 /*ARGSUSED*/
253 static int
254 mlsvc_xa_preserve(struct mlrpc_client *mcli, struct mlrpc_xaction *mxa,
255     mlrpc_heapref_t *heapref)
256 {
257 	heapref->state = MLRPC_HRST_PRESERVED;
258 	heapref->heap = mxa->heap;
259 	heapref->recv_pdu_buf = (char *)mxa->recv_mlnds.pdu_base_addr;
260 	heapref->send_pdu_buf = (char *)mxa->send_mlnds.pdu_base_addr;
261 
262 	mxa->heap = NULL;
263 	return (0);
264 }
265 
266 /*
267  * mlsvc_xa_destruct
268  *
269  * This function is called to dispose of the heap. If the heap has
270  * been preserved via mlsvc_xa_preserve, the mxa heap pointer will
271  * be null and we assume that the heap will be released later via
272  * a call to mlsvc_xa_release. Otherwise we free the memory here.
273  */
274 /*ARGSUSED*/
275 static int
276 mlsvc_xa_destruct(struct mlrpc_client *mcli, struct mlrpc_xaction *mxa)
277 {
278 	if (mxa->heap) {
279 		mlnds_destruct(&mxa->recv_mlnds);
280 		mlnds_destruct(&mxa->send_mlnds);
281 		mlrpc_heap_destroy(mxa->heap);
282 	}
283 
284 	return (0);
285 }
286 
287 /*
288  * mlsvc_xa_release
289  *
290  * This function is called, via some indirection, as a result of a
291  * call to mlsvc_rpc_free. This is where we free the heap memory
292  * that was preserved during an RPC call.
293  */
294 /*ARGSUSED*/
295 static void
296 mlsvc_xa_release(struct mlrpc_client *mcli, mlrpc_heapref_t *heapref)
297 {
298 	if (heapref == NULL)
299 		return;
300 
301 	if (heapref->state == MLRPC_HRST_PRESERVED) {
302 		free(heapref->recv_pdu_buf);
303 		free(heapref->send_pdu_buf);
304 		mlrpc_heap_destroy(heapref->heap);
305 	}
306 }
307