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