source: mainline/uspace/lib/c/generic/adt/measured_strings.c@ 79ae36dd

lfn serial ticket/834-toolchain-update topic/msim-upgrade topic/simplify-dev-export
Last change on this file since 79ae36dd was 79ae36dd, checked in by Martin Decky <martin@…>, 14 years ago

new async framework with integrated exchange tracking

  • strict isolation between low-level IPC and high-level async framework with integrated exchange tracking
    • each IPC connection is represented by an async_sess_t structure
    • each IPC exchange is represented by an async_exch_t structure
    • exchange management is either based on atomic messages (EXCHANGE_ATOMIC), locking (EXCHANGE_SERIALIZE) or connection cloning (EXCHANGE_CLONE)
  • async_obsolete: temporary compatibility layer to keep old async clients working (several pieces of code are currently broken, but only non-essential functionality)
  • IPC_M_PHONE_HANGUP is now method no. 0 (for elegant boolean evaluation)
  • IPC_M_DEBUG_ALL has been renamed to IPC_M_DEBUG
  • IPC_M_PING has been removed (VFS protocol now has VFS_IN_PING)
  • console routines in libc have been rewritten for better abstraction
  • additional use for libc-private header files (FILE structure opaque to the client)
  • various cstyle changes (typos, indentation, missing externs in header files, improved comments, etc.)
  • Property mode set to 100644
File size: 11.5 KB
Line 
1/*
2 * Copyright (c) 2009 Lukas Mejdrech
3 * All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
7 * are met:
8 *
9 * - Redistributions of source code must retain the above copyright
10 * notice, this list of conditions and the following disclaimer.
11 * - Redistributions in binary form must reproduce the above copyright
12 * notice, this list of conditions and the following disclaimer in the
13 * documentation and/or other materials provided with the distribution.
14 * - The name of the author may not be used to endorse or promote products
15 * derived from this software without specific prior written permission.
16 *
17 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
18 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
19 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
20 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
21 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
22 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
23 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
24 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
25 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
26 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
27 */
28
29/** @addtogroup libc
30 * @{
31 */
32
33/** @file
34 * Character string with measured length implementation.
35 * @see measured_strings.h
36 */
37
38#include <adt/measured_strings.h>
39#include <malloc.h>
40#include <mem.h>
41#include <unistd.h>
42#include <errno.h>
43#include <async.h>
44#include <async_obsolete.h>
45
46/** Creates a new measured string bundled with a copy of the given string
47 * itself as one memory block.
48 *
49 * If the measured string is being freed, whole memory block is freed.
50 * The measured string should be used only as a constant.
51 *
52 * @param[in] string The initial character string to be stored.
53 * @param[in] length The length of the given string without the terminating
54 * zero ('\0') character. If the length is zero, the actual
55 * length is computed. The given length is used and
56 * appended with the terminating zero ('\0') character
57 * otherwise.
58 * @return The new bundled character string with measured length.
59 * @return NULL if there is not enough memory left.
60 */
61measured_string_t *
62measured_string_create_bulk(const uint8_t *string, size_t length)
63{
64 measured_string_t *new;
65
66 if (length == 0) {
67 while (string[length])
68 length++;
69 }
70 new = (measured_string_t *) malloc(sizeof(measured_string_t) +
71 (sizeof(uint8_t) * (length + 1)));
72 if (!new)
73 return NULL;
74
75 new->length = length;
76 new->value = ((uint8_t *) new) + sizeof(measured_string_t);
77 /* Append terminating zero explicitly - to be safe */
78 memcpy(new->value, string, new->length);
79 new->value[new->length] = '\0';
80
81 return new;
82}
83
84/** Copies the given measured string with separated header and data parts.
85 *
86 * @param[in] source The source measured string to be copied.
87 * @return The copy of the given measured string.
88 * @return NULL if the source parameter is NULL.
89 * @return NULL if there is not enough memory left.
90 */
91measured_string_t *measured_string_copy(measured_string_t *source)
92{
93 measured_string_t *new;
94
95 if (!source)
96 return NULL;
97
98 new = (measured_string_t *) malloc(sizeof(measured_string_t));
99 if (new) {
100 new->value = (uint8_t *) malloc(source->length + 1);
101 if (new->value) {
102 new->length = source->length;
103 memcpy(new->value, source->value, new->length);
104 new->value[new->length] = '\0';
105 return new;
106 }
107 free(new);
108 }
109
110 return NULL;
111}
112
113/** Receives a measured strings array from a calling module.
114 *
115 * Creates the array and the data memory blocks.
116 * This method should be used only while processing IPC messages as the array
117 * size has to be negotiated in advance.
118 *
119 * @param[out] strings The received measured strings array.
120 * @param[out] data The measured strings data. This memory block stores the
121 * actual character strings.
122 * @param[in] count The size of the measured strings array.
123 * @return EOK on success.
124 * @return EINVAL if the strings or data parameter is NULL.
125 * @return EINVAL if the count parameter is zero (0).
126 * @return EINVAL if the sent array differs in size.
127 * @return EINVAL if there is inconsistency in sent measured
128 * strings' lengths (should not occur).
129 * @return ENOMEM if there is not enough memory left.
130 * @return Other error codes as defined for the
131 * async_data_write_finalize() function.
132 */
133int
134measured_strings_receive(measured_string_t **strings, uint8_t **data,
135 size_t count)
136{
137 size_t *lengths;
138 size_t index;
139 size_t length;
140 uint8_t *next;
141 ipc_callid_t callid;
142 int rc;
143
144 if ((!strings) || (!data) || (count <= 0))
145 return EINVAL;
146
147 lengths = (size_t *) malloc(sizeof(size_t) * (count + 1));
148 if (!lengths)
149 return ENOMEM;
150
151 if ((!async_data_write_receive(&callid, &length)) ||
152 (length != sizeof(size_t) * (count + 1))) {
153 free(lengths);
154 return EINVAL;
155 }
156 rc = async_data_write_finalize(callid, lengths, length);
157 if (rc != EOK) {
158 free(lengths);
159 return rc;
160 }
161
162 *data = malloc(lengths[count]);
163 if (!*data) {
164 free(lengths);
165 return ENOMEM;
166 }
167 (*data)[lengths[count] - 1] = '\0';
168
169 *strings = (measured_string_t *) malloc(sizeof(measured_string_t) *
170 count);
171 if (!*strings) {
172 free(lengths);
173 free(*data);
174 return ENOMEM;
175 }
176
177 next = *data;
178 for (index = 0; index < count; index++) {
179 (*strings)[index].length = lengths[index];
180 if (lengths[index] > 0) {
181 if (!async_data_write_receive(&callid, &length) ||
182 (length != lengths[index])) {
183 free(*data);
184 free(*strings);
185 free(lengths);
186 return EINVAL;
187 }
188 rc = async_data_write_finalize(callid, next,
189 lengths[index]);
190 if (rc != EOK) {
191 free(*data);
192 free(*strings);
193 free(lengths);
194 return rc;
195 }
196 (*strings)[index].value = next;
197 next += lengths[index];
198 *next++ = '\0';
199 } else {
200 (*strings)[index].value = NULL;
201 }
202 }
203
204 free(lengths);
205 return EOK;
206}
207
208/** Computes the lengths of the measured strings in the given array.
209 *
210 * @param[in] strings The measured strings array to be processed.
211 * @param[in] count The measured strings array size.
212 * @return The computed sizes array.
213 * @return NULL if there is not enough memory left.
214 */
215static size_t *prepare_lengths(const measured_string_t *strings, size_t count)
216{
217 size_t *lengths;
218 size_t index;
219 size_t length;
220
221 lengths = (size_t *) malloc(sizeof(size_t) * (count + 1));
222 if (!lengths)
223 return NULL;
224
225 length = 0;
226 for (index = 0; index < count; index++) {
227 lengths[index] = strings[index].length;
228 length += lengths[index] + 1;
229 }
230 lengths[count] = length;
231 return lengths;
232}
233
234/** Replies the given measured strings array to a calling module.
235 *
236 * This method should be used only while processing IPC messages as the array
237 * size has to be negotiated in advance.
238 *
239 * @param[in] strings The measured strings array to be transferred.
240 * @param[in] count The measured strings array size.
241 * @return EOK on success.
242 * @return EINVAL if the strings parameter is NULL.
243 * @return EINVAL if the count parameter is zero (0).
244 * @return EINVAL if the calling module does not accept the given
245 * array size.
246 * @return EINVAL if there is inconsistency in sent measured
247 * strings' lengths (should not occur).
248 * @return Other error codes as defined for the
249 * async_data_read_finalize() function.
250 */
251int measured_strings_reply(const measured_string_t *strings, size_t count)
252{
253 size_t *lengths;
254 size_t index;
255 size_t length;
256 ipc_callid_t callid;
257 int rc;
258
259 if ((!strings) || (count <= 0))
260 return EINVAL;
261
262 lengths = prepare_lengths(strings, count);
263 if (!lengths)
264 return ENOMEM;
265
266 if (!async_data_read_receive(&callid, &length) ||
267 (length != sizeof(size_t) * (count + 1))) {
268 free(lengths);
269 return EINVAL;
270 }
271 rc = async_data_read_finalize(callid, lengths, length);
272 if (rc != EOK) {
273 free(lengths);
274 return rc;
275 }
276 free(lengths);
277
278 for (index = 0; index < count; index++) {
279 if (strings[index].length > 0) {
280 if (!async_data_read_receive(&callid, &length) ||
281 (length != strings[index].length)) {
282 return EINVAL;
283 }
284 rc = async_data_read_finalize(callid,
285 strings[index].value, strings[index].length);
286 if (rc != EOK)
287 return rc;
288 }
289 }
290
291 return EOK;
292}
293
294/** Receives a measured strings array from another module.
295 *
296 * Creates the array and the data memory blocks.
297 * This method should be used only following other IPC messages as the array
298 * size has to be negotiated in advance.
299 *
300 * @param[in] phone The other module phone.
301 * @param[out] strings The returned measured strings array.
302 * @param[out] data The measured strings data. This memory block stores the
303 * actual character strings.
304 * @param[in] count The size of the measured strings array.
305 * @return EOK on success.
306 * @return EINVAL if the strings or data parameter is NULL.
307 * @return EINVAL if the phone or count parameter is not positive.
308 * @return EINVAL if the sent array differs in size.
309 * @return ENOMEM if there is not enough memory left.
310 * @return Other error codes as defined for the
311 * async_data_read_start() function.
312 */
313int
314measured_strings_return(int phone, measured_string_t **strings, uint8_t **data,
315 size_t count)
316{
317 size_t *lengths;
318 size_t index;
319 uint8_t *next;
320 int rc;
321
322 if ((phone < 0) || (!strings) || (!data) || (count <= 0))
323 return EINVAL;
324
325 lengths = (size_t *) malloc(sizeof(size_t) * (count + 1));
326 if (!lengths)
327 return ENOMEM;
328
329 rc = async_obsolete_data_read_start(phone, lengths,
330 sizeof(size_t) * (count + 1));
331 if (rc != EOK) {
332 free(lengths);
333 return rc;
334 }
335
336 *data = malloc(lengths[count]);
337 if (!*data) {
338 free(lengths);
339 return ENOMEM;
340 }
341
342 *strings = (measured_string_t *) malloc(sizeof(measured_string_t) *
343 count);
344 if (!*strings) {
345 free(lengths);
346 free(*data);
347 return ENOMEM;
348 }
349
350 next = *data;
351 for (index = 0; index < count; index++) {
352 (*strings)[index].length = lengths[index];
353 if (lengths[index] > 0) {
354 rc = async_obsolete_data_read_start(phone, next, lengths[index]);
355 if (rc != EOK) {
356 free(lengths);
357 free(data);
358 free(strings);
359 return rc;
360 }
361 (*strings)[index].value = next;
362 next += lengths[index];
363 *next++ = '\0';
364 } else {
365 (*strings)[index].value = NULL;
366 }
367 }
368
369 free(lengths);
370 return EOK;
371}
372
373/** Sends the given measured strings array to another module.
374 *
375 * This method should be used only following other IPC messages as the array
376 * size has to be negotiated in advance.
377 *
378 * @param[in] phone The other module phone.
379 * @param[in] strings The measured strings array to be transferred.
380 * @param[in] count The measured strings array size.
381 * @return EOK on success.
382 * @return EINVAL if the strings parameter is NULL.
383 * @return EINVAL if the phone or count parameter is not positive.
384 * @return Other error codes as defined for the
385 * async_data_write_start() function.
386 */
387int
388measured_strings_send(int phone, const measured_string_t *strings,
389 size_t count)
390{
391 size_t *lengths;
392 size_t index;
393 int rc;
394
395 if ((phone < 0) || (!strings) || (count <= 0))
396 return EINVAL;
397
398 lengths = prepare_lengths(strings, count);
399 if (!lengths)
400 return ENOMEM;
401
402 rc = async_obsolete_data_write_start(phone, lengths,
403 sizeof(size_t) * (count + 1));
404 if (rc != EOK) {
405 free(lengths);
406 return rc;
407 }
408
409 free(lengths);
410
411 for (index = 0; index < count; index++) {
412 if (strings[index].length > 0) {
413 rc = async_obsolete_data_write_start(phone, strings[index].value,
414 strings[index].length);
415 if (rc != EOK)
416 return rc;
417 }
418 }
419
420 return EOK;
421}
422
423/** @}
424 */
425
Note: See TracBrowser for help on using the repository browser.