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
RevLine 
[21580dd]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
[2544442]29/** @addtogroup libc
[21580dd]30 * @{
31 */
32
33/** @file
[edba2b6f]34 * Character string with measured length implementation.
35 * @see measured_strings.h
[21580dd]36 */
37
[7390870]38#include <adt/measured_strings.h>
[21580dd]39#include <malloc.h>
40#include <mem.h>
41#include <unistd.h>
[c5b59ce]42#include <errno.h>
[7390870]43#include <async.h>
[79ae36dd]44#include <async_obsolete.h>
[21580dd]45
[edba2b6f]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
[d2b1040]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
[edba2b6f]57 * otherwise.
[1bfd3d3]58 * @return The new bundled character string with measured length.
59 * @return NULL if there is not enough memory left.
[edba2b6f]60 */
[4eca056]61measured_string_t *
[61bfc370]62measured_string_create_bulk(const uint8_t *string, size_t length)
[edba2b6f]63{
[4eca056]64 measured_string_t *new;
[21580dd]65
[edba2b6f]66 if (length == 0) {
67 while (string[length])
[d2b1040]68 length++;
[aadf01e]69 }
[4eca056]70 new = (measured_string_t *) malloc(sizeof(measured_string_t) +
[61bfc370]71 (sizeof(uint8_t) * (length + 1)));
[edba2b6f]72 if (!new)
[aadf01e]73 return NULL;
[edba2b6f]74
[21580dd]75 new->length = length;
[61bfc370]76 new->value = ((uint8_t *) new) + sizeof(measured_string_t);
[28a3e74]77 /* Append terminating zero explicitly - to be safe */
[aadf01e]78 memcpy(new->value, string, new->length);
79 new->value[new->length] = '\0';
[edba2b6f]80
[21580dd]81 return new;
82}
83
[edba2b6f]84/** Copies the given measured string with separated header and data parts.
85 *
86 * @param[in] source The source measured string to be copied.
[1bfd3d3]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.
[edba2b6f]90 */
[4eca056]91measured_string_t *measured_string_copy(measured_string_t *source)
[edba2b6f]92{
[4eca056]93 measured_string_t *new;
[21580dd]94
[edba2b6f]95 if (!source)
[aadf01e]96 return NULL;
[edba2b6f]97
[4eca056]98 new = (measured_string_t *) malloc(sizeof(measured_string_t));
[edba2b6f]99 if (new) {
[61bfc370]100 new->value = (uint8_t *) malloc(source->length + 1);
[edba2b6f]101 if (new->value) {
[21580dd]102 new->length = source->length;
[aadf01e]103 memcpy(new->value, source->value, new->length);
104 new->value[new->length] = '\0';
[21580dd]105 return new;
106 }
[d2b1040]107 free(new);
[21580dd]108 }
[edba2b6f]109
[21580dd]110 return NULL;
111}
112
[edba2b6f]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.
[1bfd3d3]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
[edba2b6f]128 * strings' lengths (should not occur).
[1bfd3d3]129 * @return ENOMEM if there is not enough memory left.
130 * @return Other error codes as defined for the
[edba2b6f]131 * async_data_write_finalize() function.
132 */
133int
[61bfc370]134measured_strings_receive(measured_string_t **strings, uint8_t **data,
[edba2b6f]135 size_t count)
136{
137 size_t *lengths;
[aadf01e]138 size_t index;
139 size_t length;
[61bfc370]140 uint8_t *next;
[aadf01e]141 ipc_callid_t callid;
[278b97b1]142 int rc;
[21580dd]143
[edba2b6f]144 if ((!strings) || (!data) || (count <= 0))
[21580dd]145 return EINVAL;
[edba2b6f]146
[aadf01e]147 lengths = (size_t *) malloc(sizeof(size_t) * (count + 1));
[edba2b6f]148 if (!lengths)
[aadf01e]149 return ENOMEM;
[edba2b6f]150
151 if ((!async_data_write_receive(&callid, &length)) ||
152 (length != sizeof(size_t) * (count + 1))) {
[aadf01e]153 free(lengths);
[21580dd]154 return EINVAL;
155 }
[278b97b1]156 rc = async_data_write_finalize(callid, lengths, length);
157 if (rc != EOK) {
[aadf01e]158 free(lengths);
[278b97b1]159 return rc;
[21580dd]160 }
[0402bda5]161
[aadf01e]162 *data = malloc(lengths[count]);
[d2b1040]163 if (!*data) {
[0402bda5]164 free(lengths);
[aadf01e]165 return ENOMEM;
166 }
167 (*data)[lengths[count] - 1] = '\0';
[edba2b6f]168
[4eca056]169 *strings = (measured_string_t *) malloc(sizeof(measured_string_t) *
[edba2b6f]170 count);
[d2b1040]171 if (!*strings) {
[aadf01e]172 free(lengths);
173 free(*data);
[21580dd]174 return ENOMEM;
175 }
[edba2b6f]176
177 next = *data;
[d2b1040]178 for (index = 0; index < count; index++) {
[aadf01e]179 (*strings)[index].length = lengths[index];
[edba2b6f]180 if (lengths[index] > 0) {
[d2b1040]181 if (!async_data_write_receive(&callid, &length) ||
[edba2b6f]182 (length != lengths[index])) {
[aadf01e]183 free(*data);
184 free(*strings);
185 free(lengths);
[21580dd]186 return EINVAL;
187 }
[278b97b1]188 rc = async_data_write_finalize(callid, next,
189 lengths[index]);
190 if (rc != EOK) {
[f4c8a83f]191 free(*data);
192 free(*strings);
193 free(lengths);
[278b97b1]194 return rc;
[f4c8a83f]195 }
[aadf01e]196 (*strings)[index].value = next;
197 next += lengths[index];
[d2b1040]198 *next++ = '\0';
[edba2b6f]199 } else {
[aadf01e]200 (*strings)[index].value = NULL;
[21580dd]201 }
202 }
[edba2b6f]203
[aadf01e]204 free(lengths);
[21580dd]205 return EOK;
206}
207
[849ed54]208/** Computes the lengths of the measured strings in the given array.
[edba2b6f]209 *
210 * @param[in] strings The measured strings array to be processed.
211 * @param[in] count The measured strings array size.
[1bfd3d3]212 * @return The computed sizes array.
213 * @return NULL if there is not enough memory left.
[849ed54]214 */
[4eca056]215static size_t *prepare_lengths(const measured_string_t *strings, size_t count)
[edba2b6f]216{
217 size_t *lengths;
[849ed54]218 size_t index;
219 size_t length;
220
221 lengths = (size_t *) malloc(sizeof(size_t) * (count + 1));
[edba2b6f]222 if (!lengths)
[849ed54]223 return NULL;
[edba2b6f]224
[849ed54]225 length = 0;
[d2b1040]226 for (index = 0; index < count; index++) {
[849ed54]227 lengths[index] = strings[index].length;
228 length += lengths[index] + 1;
229 }
230 lengths[count] = length;
231 return lengths;
232}
233
[edba2b6f]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.
[1bfd3d3]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
[edba2b6f]245 * array size.
[1bfd3d3]246 * @return EINVAL if there is inconsistency in sent measured
[edba2b6f]247 * strings' lengths (should not occur).
[1bfd3d3]248 * @return Other error codes as defined for the
[edba2b6f]249 * async_data_read_finalize() function.
250 */
[4eca056]251int measured_strings_reply(const measured_string_t *strings, size_t count)
[edba2b6f]252{
253 size_t *lengths;
[aadf01e]254 size_t index;
255 size_t length;
256 ipc_callid_t callid;
[278b97b1]257 int rc;
[21580dd]258
[edba2b6f]259 if ((!strings) || (count <= 0))
[21580dd]260 return EINVAL;
[edba2b6f]261
[aadf01e]262 lengths = prepare_lengths(strings, count);
[edba2b6f]263 if (!lengths)
[aadf01e]264 return ENOMEM;
[edba2b6f]265
[d2b1040]266 if (!async_data_read_receive(&callid, &length) ||
[edba2b6f]267 (length != sizeof(size_t) * (count + 1))) {
[aadf01e]268 free(lengths);
[21580dd]269 return EINVAL;
270 }
[278b97b1]271 rc = async_data_read_finalize(callid, lengths, length);
272 if (rc != EOK) {
[aadf01e]273 free(lengths);
[278b97b1]274 return rc;
[21580dd]275 }
[aadf01e]276 free(lengths);
[edba2b6f]277
[d2b1040]278 for (index = 0; index < count; index++) {
[edba2b6f]279 if (strings[index].length > 0) {
[d2b1040]280 if (!async_data_read_receive(&callid, &length) ||
[edba2b6f]281 (length != strings[index].length)) {
[21580dd]282 return EINVAL;
283 }
[278b97b1]284 rc = async_data_read_finalize(callid,
285 strings[index].value, strings[index].length);
286 if (rc != EOK)
287 return rc;
[21580dd]288 }
289 }
[edba2b6f]290
[21580dd]291 return EOK;
292}
293
[edba2b6f]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.
[1bfd3d3]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
[edba2b6f]311 * async_data_read_start() function.
312 */
313int
[61bfc370]314measured_strings_return(int phone, measured_string_t **strings, uint8_t **data,
[edba2b6f]315 size_t count)
316{
317 size_t *lengths;
[aadf01e]318 size_t index;
[61bfc370]319 uint8_t *next;
[278b97b1]320 int rc;
[21580dd]321
[d2b1040]322 if ((phone < 0) || (!strings) || (!data) || (count <= 0))
[21580dd]323 return EINVAL;
[edba2b6f]324
[aadf01e]325 lengths = (size_t *) malloc(sizeof(size_t) * (count + 1));
[edba2b6f]326 if (!lengths)
[aadf01e]327 return ENOMEM;
[edba2b6f]328
[79ae36dd]329 rc = async_obsolete_data_read_start(phone, lengths,
[278b97b1]330 sizeof(size_t) * (count + 1));
331 if (rc != EOK) {
[aadf01e]332 free(lengths);
[278b97b1]333 return rc;
[21580dd]334 }
[edba2b6f]335
[aadf01e]336 *data = malloc(lengths[count]);
[d2b1040]337 if (!*data) {
[0402bda5]338 free(lengths);
[aadf01e]339 return ENOMEM;
340 }
[edba2b6f]341
[4eca056]342 *strings = (measured_string_t *) malloc(sizeof(measured_string_t) *
[edba2b6f]343 count);
[d2b1040]344 if (!*strings) {
[aadf01e]345 free(lengths);
346 free(*data);
[21580dd]347 return ENOMEM;
348 }
[edba2b6f]349
350 next = *data;
[d2b1040]351 for (index = 0; index < count; index++) {
[aadf01e]352 (*strings)[index].length = lengths[index];
[edba2b6f]353 if (lengths[index] > 0) {
[79ae36dd]354 rc = async_obsolete_data_read_start(phone, next, lengths[index]);
[278b97b1]355 if (rc != EOK) {
[f4c8a83f]356 free(lengths);
357 free(data);
358 free(strings);
[278b97b1]359 return rc;
[f4c8a83f]360 }
[aadf01e]361 (*strings)[index].value = next;
362 next += lengths[index];
[d2b1040]363 *next++ = '\0';
[edba2b6f]364 } else {
[aadf01e]365 (*strings)[index].value = NULL;
[21580dd]366 }
367 }
[edba2b6f]368
[aadf01e]369 free(lengths);
[21580dd]370 return EOK;
371}
372
[edba2b6f]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.
[1bfd3d3]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
[edba2b6f]385 * async_data_write_start() function.
386 */
387int
[4eca056]388measured_strings_send(int phone, const measured_string_t *strings,
[edba2b6f]389 size_t count)
390{
391 size_t *lengths;
[aadf01e]392 size_t index;
[278b97b1]393 int rc;
[21580dd]394
[d2b1040]395 if ((phone < 0) || (!strings) || (count <= 0))
[21580dd]396 return EINVAL;
[edba2b6f]397
[aadf01e]398 lengths = prepare_lengths(strings, count);
[edba2b6f]399 if (!lengths)
[aadf01e]400 return ENOMEM;
[edba2b6f]401
[79ae36dd]402 rc = async_obsolete_data_write_start(phone, lengths,
[278b97b1]403 sizeof(size_t) * (count + 1));
404 if (rc != EOK) {
[aadf01e]405 free(lengths);
[278b97b1]406 return rc;
[21580dd]407 }
[edba2b6f]408
[aadf01e]409 free(lengths);
[edba2b6f]410
[d2b1040]411 for (index = 0; index < count; index++) {
[edba2b6f]412 if (strings[index].length > 0) {
[79ae36dd]413 rc = async_obsolete_data_write_start(phone, strings[index].value,
[278b97b1]414 strings[index].length);
415 if (rc != EOK)
416 return rc;
[21580dd]417 }
418 }
[edba2b6f]419
[21580dd]420 return EOK;
421}
422
423/** @}
424 */
425
Note: See TracBrowser for help on using the repository browser.