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.
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.
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]
22 * Copyright 2009 Sun Microsystems, Inc. All rights reserved.
23 * Use is subject to license terms.
25 * Copyright 2013 Nexenta Systems, Inc. All rights reserved.
29 * NDR heap management. The heap is used for temporary storage by
30 * both the client and server side library routines. In order to
31 * support the different requirements of the various RPCs, the heap
32 * can grow dynamically if required. We start with a single block
33 * and perform sub-allocations from it. If an RPC requires more space
34 * we will continue to add it a block at a time. This means that we
35 * don't hog lots of memory on every call to support the few times
36 * that we actually need a lot heap space.
38 * Note that there is no individual free function. Once space has been
39 * allocated, it remains allocated until the heap is destroyed. This
40 * shouldn't be an issue because the heap is being filled with data to
41 * be marshalled or unmarshalled and we need it all to be there until
42 * the point that the entire heap is no longer required.
45 #include <sys/errno.h>
52 #include <ndr_wchar.h>
55 * Allocate a heap structure and the first heap block. For many RPC
56 * operations this will be the only time we need to malloc memory
57 * in this instance of the heap. The only point of note here is that
58 * we put the heap management data in the first block to avoid a
59 * second malloc. Make sure that sizeof(ndr_heap_t) is smaller
60 * than NDR_HEAP_BLKSZ.
62 * Note that the heap management data is at the start of the first block.
64 * Returns a pointer to the newly created heap, which is used like an
65 * opaque handle with the rest of the heap management interface..
72 size_t allocsize
= sizeof (ndr_heap_t
) + NDR_HEAP_BLKSZ
;
74 if ((heap
= malloc(allocsize
)) == NULL
)
78 bzero(heap
, sizeof (ndr_heap_t
));
80 heap
->iovcnt
= NDR_HEAP_MAXIOV
;
81 heap
->iov
= heap
->iovec
;
82 heap
->iov
->iov_base
= base
;
83 heap
->iov
->iov_len
= sizeof (ndr_heap_t
);
84 heap
->top
= base
+ allocsize
;
85 heap
->next
= base
+ sizeof (ndr_heap_t
);
91 * Deallocate all of the memory associated with a heap. This is the
92 * only way to deallocate heap memory, it isn't possible to free the
93 * space obtained by individual malloc calls.
95 * Note that the first block contains the heap management data, which
99 ndr_heap_destroy(ndr_heap_t
*heap
)
105 for (i
= 1; i
< NDR_HEAP_MAXIOV
; ++i
) {
106 if ((p
= heap
->iovec
[i
].iov_base
) != NULL
)
115 * Allocate space in the specified heap. All requests are padded, if
116 * required, to ensure dword alignment. If the current iov will be
117 * exceeded, we allocate a new block and setup the next iov. Otherwise
118 * all we have to do is move the next pointer and update the current
121 * On success, a pointer to the allocated (dword aligned) area is
122 * returned. Otherwise a null pointer is returned.
125 ndr_heap_malloc(ndr_heap_t
*heap
, unsigned size
)
130 size
+= NDR_ALIGN4(size
);
132 if (heap
== NULL
|| size
== 0)
137 if (p
+ size
> heap
->top
) {
138 if ((heap
->iovcnt
== 0) || ((--heap
->iovcnt
) == 0))
141 incr_size
= (size
< NDR_HEAP_BLKSZ
) ? NDR_HEAP_BLKSZ
: size
;
143 if ((p
= (char *)malloc(incr_size
)) == NULL
)
147 heap
->iov
->iov_base
= p
;
148 heap
->iov
->iov_len
= 0;
149 heap
->top
= p
+ incr_size
;
152 heap
->next
= p
+ size
;
153 heap
->iov
->iov_len
+= size
;
158 * Convenience function to copy some memory into the heap.
161 ndr_heap_dupmem(ndr_heap_t
*heap
, const void *mem
, size_t len
)
168 if ((p
= ndr_heap_malloc(heap
, len
)) != NULL
)
169 (void) memcpy(p
, mem
, len
);
175 * Convenience function to do heap strdup.
178 ndr_heap_strdup(ndr_heap_t
*heap
, const char *s
)
187 * We don't need to clutter the heap with empty strings.
189 if ((len
= strlen(s
)) == 0)
192 p
= ndr_heap_dupmem(heap
, s
, len
+1);
198 * Make an ndr_mstring_t from a regular string.
201 ndr_heap_mstring(ndr_heap_t
*heap
, const char *s
, ndr_mstring_t
*out
)
205 if (s
== NULL
|| out
== NULL
)
209 * Determine the WC strlen of s
210 * Was ndr__wcequiv_strlen(s)
212 slen
= ndr__mbstowcs(NULL
, s
, NDR_STRING_MAX
);
213 if (slen
== (size_t)-1)
216 out
->length
= slen
* sizeof (ndr_wchar_t
);
217 out
->allosize
= out
->length
+ sizeof (ndr_wchar_t
);
219 if ((out
->str
= ndr_heap_strdup(heap
, s
)) == NULL
)
226 * Our regular string marshalling always creates null terminated strings
227 * but some Windows clients and servers are pedantic about the string
228 * formats they will accept and require non-null terminated strings.
229 * This function can be used to build a wide-char, non-null terminated
230 * string in the heap as a varying/conformant array. We need to do the
231 * wide-char conversion here because the marshalling code won't be
232 * aware that this is really a string.
235 ndr_heap_mkvcs(ndr_heap_t
*heap
, char *s
, ndr_vcstr_t
*vc
)
241 * Determine the WC strlen of s
242 * Was ndr__wcequiv_strlen(s)
244 slen
= ndr__mbstowcs(NULL
, s
, NDR_STRING_MAX
);
245 if (slen
== (size_t)-1)
248 vc
->wclen
= slen
* sizeof (ndr_wchar_t
);
249 vc
->wcsize
= vc
->wclen
;
252 * alloc one extra wchar for a null
253 * See slen + 1 arg for mbstowcs
255 mlen
= sizeof (ndr_vcs_t
) + vc
->wcsize
+ sizeof (ndr_wchar_t
);
256 vc
->vcs
= ndr_heap_malloc(heap
, mlen
);
259 vc
->vcs
->vc_first_is
= 0;
260 vc
->vcs
->vc_length_is
= slen
;
261 (void) ndr__mbstowcs(vc
->vcs
->buffer
, s
, slen
+ 1);
266 ndr_heap_mkvcb(ndr_heap_t
*heap
, uint8_t *data
, uint32_t datalen
,
271 if (data
== NULL
|| datalen
== 0) {
272 bzero(vcbuf
, sizeof (ndr_vcbuf_t
));
276 vcbuf
->len
= datalen
;
277 vcbuf
->size
= datalen
;
279 mlen
= sizeof (ndr_vcbuf_t
) + datalen
;
281 vcbuf
->vcb
= ndr_heap_malloc(heap
, mlen
);
284 vcbuf
->vcb
->vc_first_is
= 0;
285 vcbuf
->vcb
->vc_length_is
= datalen
;
286 bcopy(data
, vcbuf
->vcb
->buffer
, datalen
);
291 * Removed ndr_heap_siddup(), now using ndr_heap_dupmem().
295 ndr_heap_used(ndr_heap_t
*heap
)
300 for (i
= 0; i
< NDR_HEAP_MAXIOV
; ++i
)
301 used
+= heap
->iovec
[i
].iov_len
;
307 ndr_heap_avail(ndr_heap_t
*heap
)
312 count
= (heap
->iovcnt
== 0) ? 0 : (heap
->iovcnt
- 1);
314 avail
= count
* NDR_HEAP_BLKSZ
;
315 avail
+= (heap
->top
- heap
->next
);