Index: uspace/lib/socket/adt/measured_strings.c
===================================================================
--- uspace/lib/socket/adt/measured_strings.c	(revision 849ed54afbef3ad0ec3af831e93a1353f9eaaf0f)
+++ uspace/lib/socket/adt/measured_strings.c	(revision 849ed54afbef3ad0ec3af831e93a1353f9eaaf0f)
@@ -0,0 +1,284 @@
+/*
+ * Copyright (c) 2009 Lukas Mejdrech
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * - Redistributions of source code must retain the above copyright
+ *   notice, this list of conditions and the following disclaimer.
+ * - Redistributions in binary form must reproduce the above copyright
+ *   notice, this list of conditions and the following disclaimer in the
+ *   documentation and/or other materials provided with the distribution.
+ * - The name of the author may not be used to endorse or promote products
+ *   derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+/** @addtogroup net
+ *  @{
+ */
+
+/** @file
+ *  Character string with measured length implementation.
+ *  @see measured_strings.h
+ */
+
+#include <errno.h>
+#include <malloc.h>
+#include <mem.h>
+#include <unistd.h>
+
+#include <ipc/ipc.h>
+
+#include <net_err.h>
+#include <net_modules.h>
+#include <adt/measured_strings.h>
+
+measured_string_ref measured_string_create_bulk(const char * string, size_t length){
+	measured_string_ref new;
+
+	if(length == 0){
+		while(string[length]){
+			++ length;
+		}
+	}
+	new = (measured_string_ref) malloc(sizeof(measured_string_t) + (sizeof(char) * (length + 1)));
+	if(! new){
+		return NULL;
+	}
+	new->length = length;
+	new->value = ((char *) new) + sizeof(measured_string_t);
+	// append terminating zero explicitly - to be safe
+	memcpy(new->value, string, new->length);
+	new->value[new->length] = '\0';
+	return new;
+}
+
+measured_string_ref measured_string_copy(measured_string_ref source){
+	measured_string_ref new;
+
+	if(! source){
+		return NULL;
+	}
+	new = (measured_string_ref) malloc(sizeof(measured_string_t));
+	if(new){
+		new->value = (char *) malloc(source->length + 1);
+		if(new->value){
+			new->length = source->length;
+			memcpy(new->value, source->value, new->length);
+			new->value[new->length] = '\0';
+			return new;
+		}else{
+			free(new);
+		}
+	}
+	return NULL;
+}
+
+int measured_strings_receive(measured_string_ref * strings, char ** data, size_t count){
+	ERROR_DECLARE;
+
+	size_t * lengths;
+	size_t index;
+	size_t length;
+	char * next;
+	ipc_callid_t callid;
+
+	if((! strings) || (! data) || (count <= 0)){
+		return EINVAL;
+	}
+	lengths = (size_t *) malloc(sizeof(size_t) * (count + 1));
+	if(! lengths){
+		return ENOMEM;
+	}
+	if((! async_data_write_receive(&callid, &length))
+		|| (length != sizeof(size_t) * (count + 1))){
+		free(lengths);
+		return EINVAL;
+	}
+	if(ERROR_OCCURRED(async_data_write_finalize(callid, lengths, sizeof(size_t) * (count + 1)))){
+		free(lengths);
+		return ERROR_CODE;
+	}
+	*data = malloc(lengths[count]);
+	if(!(*data)){
+		return ENOMEM;
+	}
+	(*data)[lengths[count] - 1] = '\0';
+	*strings = (measured_string_ref) malloc(sizeof(measured_string_t) * count);
+	if(!(*strings)){
+		free(lengths);
+		free(*data);
+		return ENOMEM;
+	}
+	next = * data;
+	for(index = 0; index < count; ++ index){
+		(*strings)[index].length = lengths[index];
+		if(lengths[index] > 0){
+			if((! async_data_write_receive(&callid, &length))
+				|| (length != lengths[index])){
+				free(*data);
+				free(*strings);
+				free(lengths);
+				return EINVAL;
+			}
+			ERROR_PROPAGATE(async_data_write_finalize(callid, next, lengths[index]));
+			(*strings)[index].value = next;
+			next += lengths[index];
+			*next = '\0';
+			++ next;
+		}else{
+			(*strings)[index].value = NULL;
+		}
+	}
+	free(lengths);
+	return EOK;
+}
+
+/** Computes the lengths of the measured strings in the given array.
+ *  @param[in] strings The measured strings array to be processed.
+ *  @param[in] count The measured strings array size.
+ *  @returns The computed sizes array.
+ *  @returns NULL if there is not enough memory left.
+ */
+static size_t * prepare_lengths(const measured_string_ref strings, size_t count){
+	size_t * lengths;
+	size_t index;
+	size_t length;
+
+	lengths = (size_t *) malloc(sizeof(size_t) * (count + 1));
+	if(! lengths){
+		return NULL;
+	}
+	length = 0;
+	for(index = 0; index < count; ++ index){
+		lengths[index] = strings[index].length;
+		length += lengths[index] + 1;
+	}
+	lengths[count] = length;
+	return lengths;
+}
+
+int measured_strings_reply(const measured_string_ref strings, size_t count){
+	ERROR_DECLARE;
+
+	size_t * lengths;
+	size_t index;
+	size_t length;
+	ipc_callid_t callid;
+
+	if((! strings) || (count <= 0)){
+		return EINVAL;
+	}
+	lengths = prepare_lengths(strings, count);
+	if(! lengths){
+		return ENOMEM;
+	}
+	if((! async_data_read_receive(&callid, &length))
+		|| (length != sizeof(size_t) * (count + 1))){
+		free(lengths);
+		return EINVAL;
+	}
+	if(ERROR_OCCURRED(async_data_read_finalize(callid, lengths, sizeof(size_t) * (count + 1)))){
+		free(lengths);
+		return ERROR_CODE;
+	}
+	free(lengths);
+	for(index = 0; index < count; ++ index){
+		if(strings[index].length > 0){
+			if((! async_data_read_receive(&callid, &length))
+				|| (length != strings[index].length)){
+				return EINVAL;
+			}
+			ERROR_PROPAGATE(async_data_read_finalize(callid, strings[index].value, strings[index].length));
+		}
+	}
+	return EOK;
+}
+
+int measured_strings_return(int phone, measured_string_ref * strings, char ** data, size_t count){
+	ERROR_DECLARE;
+
+	size_t * lengths;
+	size_t index;
+	char * next;
+
+	if((phone <= 0) || (! strings) || (! data) || (count <= 0)){
+		return EINVAL;
+	}
+	lengths = (size_t *) malloc(sizeof(size_t) * (count + 1));
+	if(! lengths){
+		return ENOMEM;
+	}
+	if(ERROR_OCCURRED(async_data_read_start(phone, lengths, sizeof(size_t) * (count + 1)))){
+		free(lengths);
+		return ERROR_CODE;
+	}
+	*data = malloc(lengths[count]);
+	if(!(*data)){
+		return ENOMEM;
+	}
+	*strings = (measured_string_ref) malloc(sizeof(measured_string_t) * count);
+	if(!(*strings)){
+		free(lengths);
+		free(*data);
+		return ENOMEM;
+	}
+	next = * data;
+	for(index = 0; index < count; ++ index){
+		(*strings)[index].length = lengths[index];
+		if(lengths[index] > 0){
+			ERROR_PROPAGATE(async_data_read_start(phone, next, lengths[index]));
+			(*strings)[index].value = next;
+			next += lengths[index];
+			*next = '\0';
+			++ next;
+		}else{
+			(*strings)[index].value = NULL;
+		}
+	}
+	free(lengths);
+	return EOK;
+}
+
+int measured_strings_send(int phone, const measured_string_ref strings, size_t count){
+	ERROR_DECLARE;
+
+	size_t * lengths;
+	size_t index;
+
+	if((phone <= 0) || (! strings) || (count <= 0)){
+		return EINVAL;
+	}
+	lengths = prepare_lengths(strings, count);
+	if(! lengths){
+		return ENOMEM;
+	}
+	if(ERROR_OCCURRED(async_data_write_start(phone, lengths, sizeof(size_t) * (count + 1)))){
+		free(lengths);
+		return ERROR_CODE;
+	}
+	free(lengths);
+	for(index = 0; index < count; ++ index){
+		if(strings[index].length > 0){
+			ERROR_PROPAGATE(async_data_write_start(phone, strings[index].value, strings[index].length));
+		}
+	}
+	return EOK;
+}
+
+/** @}
+ */
+
