Index: uspace/app/netecho/Makefile
===================================================================
--- uspace/app/netecho/Makefile	(revision 849ed54afbef3ad0ec3af831e93a1353f9eaaf0f)
+++ uspace/app/netecho/Makefile	(revision 849ed54afbef3ad0ec3af831e93a1353f9eaaf0f)
@@ -0,0 +1,40 @@
+#
+# Copyright (c) 2005 Martin Decky
+# Copyright (c) 2007 Jakub Jermar
+# 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.
+#
+
+USPACE_PREFIX = ../..
+LIBS = $(LIBSOCKET_PREFIX)/libsocket.a
+EXTRA_CFLAGS = -I$(LIBSOCKET_PREFIX)/include
+BINARY = netecho
+
+SOURCES = \
+	netecho.c \
+	parse.c \
+	print_error.c
+
+include $(USPACE_PREFIX)/Makefile.common
Index: uspace/app/netecho/netecho.c
===================================================================
--- uspace/app/netecho/netecho.c	(revision 849ed54afbef3ad0ec3af831e93a1353f9eaaf0f)
+++ uspace/app/netecho/netecho.c	(revision 849ed54afbef3ad0ec3af831e93a1353f9eaaf0f)
@@ -0,0 +1,374 @@
+/*
+ * 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 netecho
+ *  @{
+ */
+
+/** @file
+ *  Network echo application.
+ *  Answers received packets.
+ */
+
+#include <malloc.h>
+#include <stdio.h>
+#include <str.h>
+#include <task.h>
+
+#include <in.h>
+#include <in6.h>
+#include <inet.h>
+#include <socket.h>
+#include <net_err.h>
+
+#include "parse.h"
+#include "print_error.h"
+
+/** Network echo module name.
+ */
+#define NAME	"Network Echo"
+
+/** Prints the application help.
+ */
+void echo_print_help(void);
+
+/** Module entry point.
+ *  Reads command line parameters and starts listenning.
+ *  @param[in] argc The number of command line parameters.
+ *  @param[in] argv The command line parameters.
+ *  @returns EOK on success.
+ */
+int main(int argc, char * argv[]);
+
+void echo_print_help(void){
+	printf(
+		"Network Echo aplication\n" \
+		"Usage: echo [options]\n" \
+		"Where options are:\n" \
+		"-b backlog | --backlog=size\n" \
+		"\tThe size of the accepted sockets queue. Only for SOCK_STREAM. The default is 3.\n" \
+		"\n" \
+		"-c count | --count=count\n" \
+		"\tThe number of received messages to handle. A negative number means infinity. The default is infinity.\n" \
+		"\n" \
+		"-f protocol_family | --family=protocol_family\n" \
+		"\tThe listenning socket protocol family. Only the PF_INET and PF_INET6 are supported.\n"
+		"\n" \
+		"-h | --help\n" \
+		"\tShow this application help.\n"
+		"\n" \
+		"-p port_number | --port=port_number\n" \
+		"\tThe port number the application should listen at. The default is 7.\n" \
+		"\n" \
+		"-r reply_string | --reply=reply_string\n" \
+		"\tThe constant reply string. The default is the original data received.\n" \
+		"\n" \
+		"-s receive_size | --size=receive_size\n" \
+		"\tThe maximum receive data size the application should accept. The default is 1024 bytes.\n" \
+		"\n" \
+		"-t socket_type | --type=socket_type\n" \
+		"\tThe listenning socket type. Only the SOCK_DGRAM and the SOCK_STREAM are supported.\n" \
+		"\n" \
+		"-v | --verbose\n" \
+		"\tShow all output messages.\n"
+	);
+}
+
+int main(int argc, char * argv[]){
+	ERROR_DECLARE;
+
+	size_t size			= 1024;
+	int verbose			= 0;
+	char * reply		= NULL;
+	sock_type_t type	= SOCK_DGRAM;
+	int count			= -1;
+	int family			= PF_INET;
+	uint16_t port		= 7;
+	int backlog			= 3;
+
+	socklen_t max_length				= sizeof(struct sockaddr_in6);
+	uint8_t address_data[max_length];
+	struct sockaddr * address			= (struct sockaddr *) address_data;
+	struct sockaddr_in * address_in		= (struct sockaddr_in *) address;
+	struct sockaddr_in6 * address_in6	= (struct sockaddr_in6 *) address;
+	socklen_t addrlen;
+	char address_string[INET6_ADDRSTRLEN];
+	uint8_t * address_start;
+	int socket_id;
+	int listening_id;
+	char * data;
+	size_t length;
+	int index;
+	size_t reply_length;
+	int value;
+
+	// print the program label
+	printf("Task %d - ", task_get_id());
+	printf("%s\n", NAME);
+
+	// parse the command line arguments
+	for(index = 1; index < argc; ++ index){
+		if(argv[index][0] == '-'){
+			switch(argv[index][1]){
+				case 'b':
+					ERROR_PROPAGATE(parse_parameter_int(argc, argv, &index, &backlog, "accepted sockets queue size", 0));
+					break;
+				case 'c':
+					ERROR_PROPAGATE(parse_parameter_int(argc, argv, &index, &count, "message count", 0));
+					break;
+				case 'f':
+					ERROR_PROPAGATE(parse_parameter_name_int(argc, argv, &index, &family, "protocol family", 0, parse_protocol_family));
+					break;
+				case 'h':
+					echo_print_help();
+					return EOK;
+					break;
+				case 'p':
+					ERROR_PROPAGATE(parse_parameter_int(argc, argv, &index, &value, "port number", 0));
+					port = (uint16_t) value;
+					break;
+				case 'r':
+					ERROR_PROPAGATE(parse_parameter_string(argc, argv, &index, &reply, "reply string", 0));
+					break;
+				case 's':
+					ERROR_PROPAGATE(parse_parameter_int(argc, argv, &index, &value, "receive size", 0));
+					size = (value >= 0) ? (size_t) value : 0;
+					break;
+				case 't':
+					ERROR_PROPAGATE(parse_parameter_name_int(argc, argv, &index, &value, "socket type", 0, parse_socket_type));
+					type = (sock_type_t) value;
+					break;
+				case 'v':
+					verbose = 1;
+					break;
+				// long options with the double minus sign ('-')
+				case '-':
+					if(str_lcmp(argv[index] + 2, "backlog=", 6) == 0){
+						ERROR_PROPAGATE(parse_parameter_int(argc, argv, &index, &backlog, "accepted sockets queue size", 8));
+					}else if(str_lcmp(argv[index] + 2, "count=", 6) == 0){
+						ERROR_PROPAGATE(parse_parameter_int(argc, argv, &index, &count, "message count", 8));
+					}else if(str_lcmp(argv[index] + 2, "family=", 7) == 0){
+						ERROR_PROPAGATE(parse_parameter_name_int(argc, argv, &index, &family, "protocol family", 9, parse_protocol_family));
+					}else if(str_lcmp(argv[index] + 2, "help", 5) == 0){
+						echo_print_help();
+						return EOK;
+					}else if(str_lcmp(argv[index] + 2, "port=", 5) == 0){
+						ERROR_PROPAGATE(parse_parameter_int(argc, argv, &index, &value, "port number", 7));
+						port = (uint16_t) value;
+					}else if(str_lcmp(argv[index] + 2, "reply=", 6) == 0){
+						ERROR_PROPAGATE(parse_parameter_string(argc, argv, &index, &reply, "reply string", 8));
+					}else if(str_lcmp(argv[index] + 2, "size=", 5) == 0){
+						ERROR_PROPAGATE(parse_parameter_int(argc, argv, &index, &value, "receive size", 7));
+						size = (value >= 0) ? (size_t) value : 0;
+					}else if(str_lcmp(argv[index] + 2, "type=", 5) == 0){
+						ERROR_PROPAGATE(parse_parameter_name_int(argc, argv, &index, &value, "socket type", 7, parse_socket_type));
+						type = (sock_type_t) value;
+					}else if(str_lcmp(argv[index] + 2, "verbose", 8) == 0){
+						verbose = 1;
+					}else{
+						print_unrecognized(index, argv[index] + 2);
+						echo_print_help();
+						return EINVAL;
+					}
+					break;
+				default:
+					print_unrecognized(index, argv[index] + 1);
+					echo_print_help();
+					return EINVAL;
+			}
+		}else{
+			print_unrecognized(index, argv[index]);
+			echo_print_help();
+			return EINVAL;
+		}
+	}
+
+	// check the buffer size
+	if(size <= 0){
+		fprintf(stderr, "Receive size too small (%d). Using 1024 bytes instead.\n", size);
+		size = 1024;
+	}
+	// size plus the terminating null (\0)
+	data = (char *) malloc(size + 1);
+	if(! data){
+		fprintf(stderr, "Failed to allocate receive buffer.\n");
+		return ENOMEM;
+	}
+
+	// set the reply size if set
+	reply_length = reply ? str_length(reply) : 0;
+
+	// prepare the address buffer
+	bzero(address_data, max_length);
+	switch(family){
+		case PF_INET:
+			address_in->sin_family = AF_INET;
+			address_in->sin_port = htons(port);
+			addrlen = sizeof(struct sockaddr_in);
+			break;
+		case PF_INET6:
+			address_in6->sin6_family = AF_INET6;
+			address_in6->sin6_port = htons(port);
+			addrlen = sizeof(struct sockaddr_in6);
+			break;
+		default:
+			fprintf(stderr, "Protocol family is not supported\n");
+			return EAFNOSUPPORT;
+	}
+
+	// get a listening socket
+	listening_id = socket(family, type, 0);
+	if(listening_id < 0){
+		socket_print_error(stderr, listening_id, "Socket create: ", "\n");
+		return listening_id;
+	}
+
+	// if the stream socket is used
+	if(type == SOCK_STREAM){
+		// check the backlog
+		if(backlog <= 0){
+			fprintf(stderr, "Accepted sockets queue size too small (%d). Using 3 instead.\n", size);
+			backlog = 3;
+		}
+		// set the backlog
+		if(ERROR_OCCURRED(listen(listening_id, backlog))){
+			socket_print_error(stderr, ERROR_CODE, "Socket listen: ", "\n");
+			return ERROR_CODE;
+		}
+	}
+
+	// bind the listenning socket
+	if(ERROR_OCCURRED(bind(listening_id, address, addrlen))){
+		socket_print_error(stderr, ERROR_CODE, "Socket bind: ", "\n");
+		return ERROR_CODE;
+	}
+
+	if(verbose){
+		printf("Socket %d listenning at %d\n", listening_id, port);
+	}
+
+	socket_id = listening_id;
+
+	// do count times
+	// or indefinitely if set to a negative value
+	while(count){
+
+		addrlen = max_length;
+		if(type == SOCK_STREAM){
+			// acceept a socket if the stream socket is used
+			socket_id = accept(listening_id, address, &addrlen);
+			if(socket_id <= 0){
+				socket_print_error(stderr, socket_id, "Socket accept: ", "\n");
+			}else{
+				if(verbose){
+					printf("Socket %d accepted\n", socket_id);
+				}
+			}
+		}
+
+		// if the datagram socket is used or the stream socked was accepted
+		if(socket_id > 0){
+
+			// receive an echo request
+			value = recvfrom(socket_id, data, size, 0, address, &addrlen);
+			if(value < 0){
+				socket_print_error(stderr, value, "Socket receive: ", "\n");
+			}else{
+				length = (size_t) value;
+				if(verbose){
+					// print the header
+
+					// get the source port and prepare the address buffer
+					address_start = NULL;
+					switch(address->sa_family){
+						case AF_INET:
+							port = ntohs(address_in->sin_port);
+							address_start = (uint8_t *) &address_in->sin_addr.s_addr;
+							break;
+						case AF_INET6:
+							port = ntohs(address_in6->sin6_port);
+							address_start = (uint8_t *) &address_in6->sin6_addr.s6_addr;
+							break;
+						default:
+							fprintf(stderr, "Address family %d (0x%X) is not supported.\n", address->sa_family);
+					}
+					// parse the source address
+					if(address_start){
+						if(ERROR_OCCURRED(inet_ntop(address->sa_family, address_start, address_string, sizeof(address_string)))){
+							fprintf(stderr, "Received address error %d\n", ERROR_CODE);
+						}else{
+							data[length] = '\0';
+							printf("Socket %d received %d bytes from %s:%d\n%s\n", socket_id, length, address_string, port, data);
+						}
+					}
+				}
+
+				// answer the request either with the static reply or the original data
+				if(ERROR_OCCURRED(sendto(socket_id, reply ? reply : data, reply ? reply_length : length, 0, address, addrlen))){
+					socket_print_error(stderr, ERROR_CODE, "Socket send: ", "\n");
+				}
+
+			}
+
+			// close the accepted stream socket
+			if(type == SOCK_STREAM){
+				if(ERROR_OCCURRED(closesocket(socket_id))){
+					socket_print_error(stderr, ERROR_CODE, "Close socket: ", "\n");
+				}
+			}
+
+		}
+
+		// decrease the count if positive
+		if(count > 0){
+			-- count;
+			if(verbose){
+				printf("Waiting for next %d packet(s)\n", count);
+			}
+		}
+	}
+
+	if(verbose){
+		printf("Closing the socket\n");
+	}
+
+	// close the listenning socket
+	if(ERROR_OCCURRED(closesocket(listening_id))){
+		socket_print_error(stderr, ERROR_CODE, "Close socket: ", "\n");
+		return ERROR_CODE;
+	}
+
+	if(verbose){
+		printf("Exiting\n");
+	}
+
+	return EOK;
+}
+
+/** @}
+ */
Index: uspace/app/netecho/parse.c
===================================================================
--- uspace/app/netecho/parse.c	(revision 849ed54afbef3ad0ec3af831e93a1353f9eaaf0f)
+++ uspace/app/netecho/parse.c	(revision 849ed54afbef3ad0ec3af831e93a1353f9eaaf0f)
@@ -0,0 +1,123 @@
+/*
+ * 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_app
+ *  @{
+ */
+
+/** @file
+ *  Generic application parsing functions implementation.
+ */
+
+#include <stdio.h>
+#include <str.h>
+
+#include <socket.h>
+#include <net_err.h>
+
+#include "parse.h"
+
+int parse_address_family(const char * name){
+	if(str_lcmp(name, "AF_INET", 7) == 0){
+		return AF_INET;
+	}else if(str_lcmp(name, "AF_INET6", 8) == 0){
+		return AF_INET6;
+	}
+	return EAFNOSUPPORT;
+}
+
+int parse_parameter_int(int argc, char ** argv, int * index, int * value, const char * name, int offset){
+	char * rest;
+
+	if(offset){
+		*value = strtol(argv[*index] + offset, &rest, 10);
+	}else if((*index) + 1 < argc){
+		++ (*index);
+		*value = strtol(argv[*index], &rest, 10);
+	}else{
+		fprintf(stderr, "Command line error: missing %s\n", name);
+		return EINVAL;
+	}
+	if(rest && (*rest)){
+		fprintf(stderr, "Command line error: %s unrecognized (%d: %s)\n", name, * index, argv[*index]);
+		return EINVAL;
+	}
+	return EOK;
+}
+
+int parse_parameter_name_int(int argc, char ** argv, int * index, int * value, const char * name, int offset, int (*parse_value)(const char * value)){
+	ERROR_DECLARE;
+
+	char * parameter;
+
+	ERROR_PROPAGATE(parse_parameter_string(argc, argv, index, &parameter, name, offset));
+	*value = (*parse_value)(parameter);
+	if((*value) == ENOENT){
+		fprintf(stderr, "Command line error: unrecognized %s value (%d: %s)\n", name, * index, parameter);
+		return ENOENT;
+	}
+	return EOK;
+}
+
+int parse_parameter_string(int argc, char ** argv, int * index, char ** value, const char * name, int offset){
+	if(offset){
+		*value = argv[*index] + offset;
+	}else if((*index) + 1 < argc){
+		++ (*index);
+		*value = argv[*index];
+	}else{
+		fprintf(stderr, "Command line error: missing %s\n", name);
+		return EINVAL;
+	}
+	return EOK;
+}
+
+int parse_protocol_family(const char * name){
+	if(str_lcmp(name, "PF_INET", 7) == 0){
+		return PF_INET;
+	}else if(str_lcmp(name, "PF_INET6", 8) == 0){
+		return PF_INET6;
+	}
+	return EPFNOSUPPORT;
+}
+
+int parse_socket_type(const char * name){
+	if(str_lcmp(name, "SOCK_DGRAM", 11) == 0){
+		return SOCK_DGRAM;
+	}else if(str_lcmp(name, "SOCK_STREAM", 12) == 0){
+		return SOCK_STREAM;
+	}
+	return ESOCKTNOSUPPORT;
+}
+
+void print_unrecognized(int index, const char * parameter){
+	fprintf(stderr, "Command line error: unrecognized argument (%d: %s)\n", index, parameter);
+}
+
+/** @}
+ */
Index: uspace/app/netecho/parse.h
===================================================================
--- uspace/app/netecho/parse.h	(revision 849ed54afbef3ad0ec3af831e93a1353f9eaaf0f)
+++ uspace/app/netecho/parse.h	(revision 849ed54afbef3ad0ec3af831e93a1353f9eaaf0f)
@@ -0,0 +1,120 @@
+/*
+ * 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_app
+ *  @{
+ */
+
+/** @file
+ *  Generic command line arguments parsing functions.
+ */
+
+#ifndef __NET_APP_PARSE__
+#define __NET_APP_PARSE__
+
+#include <socket.h>
+
+/** Translates the character string to the address family number.
+ *  @param[in] name The address family name.
+ *  @returns The corresponding address family number.
+ *  @returns EAFNOSUPPORTED if the address family is not supported.
+ */
+extern int parse_address_family(const char * name);
+
+/** Parses the next parameter as an integral number.
+ *  The actual parameter is pointed by the index.
+ *  Parses the offseted actual parameter value if the offset is set or the next one if not.
+ *  @param[in] argc The total number of the parameters.
+ *  @param[in] argv The parameters.
+ *  @param[in,out] index The actual parameter index. The index is incremented by the number of processed parameters.
+ *  @param[out] value The parsed parameter value.
+ *  @param[in] name The parameter name to be printed on errors.
+ *  @param[in] offset The value offset in the actual parameter. If not set, the next parameter is parsed instead.
+ *  @returns EOK on success.
+ *  @returns EINVAL if the parameter is missing.
+ *  @returns EINVAL if the parameter is in wrong format.
+ */
+extern int parse_parameter_int(int argc, char ** argv, int * index, int * value, const char * name, int offset);
+
+/** Parses the next named parameter as an integral number.
+ *  The actual parameter is pointed by the index.
+ *  Uses the offseted actual parameter if the offset is set or the next one if not.
+ *  Translates the parameter using the parse_value function.
+ *  Increments the actual index by the number of processed parameters.
+ *  @param[in] argc The total number of the parameters.
+ *  @param[in] argv The parameters.
+ *  @param[in,out] index The actual parameter index. The index is incremented by the number of processed parameters.
+ *  @param[out] value The parsed parameter value.
+ *  @param[in] name The parameter name to be printed on errors.
+ *  @param[in] offset The value offset in the actual parameter. If not set, the next parameter is parsed instead.
+ *  @param[in] parse_value The translation function to parse the named value.
+ *  @returns EOK on success.
+ *  @returns EINVAL if the parameter is missing.
+ *  @returns ENOENT if the parameter name has not been found.
+ */
+extern int parse_parameter_name_int(int argc, char ** argv, int * index, int * value, const char * name, int offset, int (*parse_value)(const char * value));
+
+/** Parses the next parameter as a character string.
+ *  The actual parameter is pointed by the index.
+ *  Uses the offseted actual parameter value if the offset is set or the next one if not.
+ *  Increments the actual index by the number of processed parameters.
+ *  @param[in] argc The total number of the parameters.
+ *  @param[in] argv The parameters.
+ *  @param[in,out] index The actual parameter index. The index is incremented by the number of processed parameters.
+ *  @param[out] value The parsed parameter value.
+ *  @param[in] name The parameter name to be printed on errors.
+ *  @param[in] offset The value offset in the actual parameter. If not set, the next parameter is parsed instead.
+ *  @returns EOK on success.
+ *  @returns EINVAL if the parameter is missing.
+ */
+extern int parse_parameter_string(int argc, char ** argv, int * index, char ** value, const char * name, int offset);
+
+/** Translates the character string to the protocol family number.
+ *  @param[in] name The protocol family name.
+ *  @returns The corresponding protocol family number.
+ *  @returns EPFNOSUPPORTED if the protocol family is not supported.
+ */
+extern int parse_protocol_family(const char * name);
+
+/** Translates the character string to the socket type number.
+ *  @param[in] name The socket type name.
+ *  @returns The corresponding socket type number.
+ *  @returns ESOCKNOSUPPORTED if the socket type is not supported.
+ */
+extern int parse_socket_type(const char * name);
+
+/** Prints the parameter unrecognized message and the application help.
+ *  @param[in] index The index of the parameter.
+ *  @param[in] parameter The parameter name.
+ */
+extern void print_unrecognized(int index, const char * parameter);
+
+#endif
+
+/** @}
+ */
Index: uspace/app/netecho/print_error.c
===================================================================
--- uspace/app/netecho/print_error.c	(revision 849ed54afbef3ad0ec3af831e93a1353f9eaaf0f)
+++ uspace/app/netecho/print_error.c	(revision 849ed54afbef3ad0ec3af831e93a1353f9eaaf0f)
@@ -0,0 +1,150 @@
+/*
+ * 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_app
+ *  @{
+ */
+
+/** @file
+ *  Generic application error printing functions implementation.
+ */
+
+#include <stdio.h>
+
+#include <icmp_codes.h>
+#include <socket_errno.h>
+
+#include "print_error.h"
+
+void icmp_print_error(FILE * output, int error_code, const char * prefix, const char * suffix){
+	if(output){
+		if(prefix){
+			fprintf(output, "%s", prefix);
+		}
+		switch(error_code){
+			case ICMP_DEST_UNREACH:
+				fprintf(output, "ICMP Destination Unreachable (%d) error", error_code);
+				break;
+			case ICMP_SOURCE_QUENCH:
+				fprintf(output, "ICMP Source Quench (%d) error", error_code);
+				break;
+			case ICMP_REDIRECT:
+				fprintf(output, "ICMP Redirect (%d) error", error_code);
+				break;
+			case ICMP_ALTERNATE_ADDR:
+				fprintf(output, "ICMP Alternate Host Address (%d) error", error_code);
+				break;
+			case ICMP_ROUTER_ADV:
+				fprintf(output, "ICMP Router Advertisement (%d) error", error_code);
+				break;
+			case ICMP_ROUTER_SOL:
+				fprintf(output, "ICMP Router Solicitation (%d) error", error_code);
+				break;
+			case ICMP_TIME_EXCEEDED:
+				fprintf(output, "ICMP Time Exceeded (%d) error", error_code);
+				break;
+			case ICMP_PARAMETERPROB:
+				fprintf(output, "ICMP Paramenter Problem (%d) error", error_code);
+				break;
+			case ICMP_CONVERSION_ERROR:
+				fprintf(output, "ICMP Datagram Conversion Error (%d) error", error_code);
+				break;
+			case ICMP_REDIRECT_MOBILE:
+				fprintf(output, "ICMP Mobile Host Redirect (%d) error", error_code);
+				break;
+			case ICMP_SKIP:
+				fprintf(output, "ICMP SKIP (%d) error", error_code);
+				break;
+			case ICMP_PHOTURIS:
+				fprintf(output, "ICMP Photuris (%d) error", error_code);
+				break;
+			default:
+				fprintf(output, "Other (%d) error", error_code);
+		}
+		if(suffix){
+			fprintf(output, "%s", suffix);
+		}
+	}
+}
+
+void print_error(FILE * output, int error_code, const char * prefix, const char * suffix){
+	if(IS_ICMP_ERROR(error_code)){
+		icmp_print_error(output, error_code, prefix, suffix);
+	}else if(IS_SOCKET_ERROR(error_code)){
+		socket_print_error(output, error_code, prefix, suffix);
+	}
+}
+
+void socket_print_error(FILE * output, int error_code, const char * prefix, const char * suffix){
+	if(output){
+		if(prefix){
+			fprintf(output, "%s", prefix);
+		}
+		switch(error_code){
+			case ENOTSOCK:
+				fprintf(output, "Not a socket (%d) error", error_code);
+				break;
+			case EPROTONOSUPPORT:
+				fprintf(output, "Protocol not supported (%d) error", error_code);
+				break;
+			case ESOCKTNOSUPPORT:
+				fprintf(output, "Socket type not supported (%d) error", error_code);
+				break;
+			case EPFNOSUPPORT:
+				fprintf(output, "Protocol family not supported (%d) error", error_code);
+				break;
+			case EAFNOSUPPORT:
+				fprintf(output, "Address family not supported (%d) error", error_code);
+				break;
+			case EADDRINUSE:
+				fprintf(output, "Address already in use (%d) error", error_code);
+				break;
+			case ENOTCONN:
+				fprintf(output, "Socket not connected (%d) error", error_code);
+				break;
+			case NO_DATA:
+				fprintf(output, "No data (%d) error", error_code);
+				break;
+			case EINPROGRESS:
+				fprintf(output, "Another operation in progress (%d) error", error_code);
+				break;
+			case EDESTADDRREQ:
+				fprintf(output, "Destination address required (%d) error", error_code);
+			case TRY_AGAIN:
+				fprintf(output, "Try again (%d) error", error_code);
+			default:
+				fprintf(output, "Other (%d) error", error_code);
+		}
+		if(suffix){
+			fprintf(output, "%s", suffix);
+		}
+	}
+}
+
+/** @}
+ */
Index: uspace/app/netecho/print_error.h
===================================================================
--- uspace/app/netecho/print_error.h	(revision 849ed54afbef3ad0ec3af831e93a1353f9eaaf0f)
+++ uspace/app/netecho/print_error.h	(revision 849ed54afbef3ad0ec3af831e93a1353f9eaaf0f)
@@ -0,0 +1,80 @@
+/*
+ * 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_app
+ *  @{
+ */
+
+/** @file
+ *  Generic application error printing functions.
+ */
+
+#ifndef __NET_APP_PRINT__
+#define __NET_APP_PRINT__
+
+/** Returns whether the error code may be an ICMP error code.
+ *  @param[in] error_code The error code.
+ *  @returns A value indicating whether the error code may be an ICMP error code.
+ */
+#define IS_ICMP_ERROR(error_code)		((error_code) > 0)
+
+/** Returns whether the error code may be socket error code.
+ *  @param[in] error_code The error code.
+ *  @returns A value indicating whether the error code may be a socket error code.
+ */
+#define IS_SOCKET_ERROR(error_code)	((error_code) < 0)
+
+/** Prints the specific ICMP error description.
+ *  @param[in] output The description output stream. May be NULL.
+ *  @param[in] error_code The ICMP error code.
+ *  @param[in] prefix The error description prefix. May be NULL.
+ *  @param[in] suffix The error description suffix. May be NULL.
+ */
+extern void icmp_print_error(FILE * output, int error_code, const char * prefix, const char * suffix);
+
+/** Prints the error description.
+ *  Supports ICMP and socket error codes.
+ *  @param[in] output The description output stream. May be NULL.
+ *  @param[in] error_code The error code.
+ *  @param[in] prefix The error description prefix. May be NULL.
+ *  @param[in] suffix The error description suffix. May be NULL.
+ */
+extern void print_error(FILE * output, int error_code, const char * prefix, const char * suffix);
+
+/** Prints the specific socket error description.
+ *  @param[in] output The description output stream. May be NULL.
+ *  @param[in] error_code The socket error code.
+ *  @param[in] prefix The error description prefix. May be NULL.
+ *  @param[in] suffix The error description suffix. May be NULL.
+ */
+extern void socket_print_error(FILE * output, int error_code, const char * prefix, const char * suffix);
+
+#endif
+
+/** @}
+ */
Index: uspace/app/nettest1/Makefile
===================================================================
--- uspace/app/nettest1/Makefile	(revision 849ed54afbef3ad0ec3af831e93a1353f9eaaf0f)
+++ uspace/app/nettest1/Makefile	(revision 849ed54afbef3ad0ec3af831e93a1353f9eaaf0f)
@@ -0,0 +1,41 @@
+#
+# Copyright (c) 2005 Martin Decky
+# Copyright (c) 2007 Jakub Jermar
+# 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.
+#
+
+USPACE_PREFIX = ../..
+LIBS = $(LIBSOCKET_PREFIX)/libsocket.a
+EXTRA_CFLAGS = -I$(LIBSOCKET_PREFIX)/include
+BINARY = nettest1
+
+SOURCES = \
+	nettest1.c \
+	nettest.c \
+	parse.c \
+	print_error.c
+
+include $(USPACE_PREFIX)/Makefile.common
Index: uspace/app/nettest1/nettest.c
===================================================================
--- uspace/app/nettest1/nettest.c	(revision 849ed54afbef3ad0ec3af831e93a1353f9eaaf0f)
+++ uspace/app/nettest1/nettest.c	(revision 849ed54afbef3ad0ec3af831e93a1353f9eaaf0f)
@@ -0,0 +1,201 @@
+/*
+ * 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 nettest
+ *  @{
+ */
+
+/** @file
+ *  Networking test support functions implementation.
+ */
+
+#include <stdio.h>
+
+#include <socket.h>
+#include <net_err.h>
+
+#include "nettest.h"
+#include "print_error.h"
+
+int sockets_create(int verbose, int * socket_ids, int sockets, int family, sock_type_t type){
+	int index;
+
+	if(verbose){
+		printf("Create\t");
+	}
+	fflush(stdout);
+	for(index = 0; index < sockets; ++ index){
+		socket_ids[index] = socket(family, type, 0);
+		if(socket_ids[index] < 0){
+			printf("Socket %d (%d) error:\n", index, socket_ids[index]);
+			socket_print_error(stderr, socket_ids[index], "Socket create: ", "\n");
+			return socket_ids[index];
+		}
+		if(verbose){
+			print_mark(index);
+		}
+	}
+	return EOK;
+}
+
+int sockets_close(int verbose, int * socket_ids, int sockets){
+	ERROR_DECLARE;
+
+	int index;
+
+	if(verbose){
+		printf("\tClose\t");
+	}
+	fflush(stdout);
+	for(index = 0; index < sockets; ++ index){
+		if(ERROR_OCCURRED(closesocket(socket_ids[index]))){
+			printf("Socket %d (%d) error:\n", index, socket_ids[index]);
+			socket_print_error(stderr, ERROR_CODE, "Socket close: ", "\n");
+			return ERROR_CODE;
+		}
+		if(verbose){
+			print_mark(index);
+		}
+	}
+	return EOK;
+}
+
+int sockets_connect(int verbose, int * socket_ids, int sockets, struct sockaddr * address, socklen_t addrlen){
+	ERROR_DECLARE;
+
+	int index;
+
+	if(verbose){
+		printf("\tConnect\t");
+	}
+	fflush(stdout);
+	for(index = 0; index < sockets; ++ index){
+		if(ERROR_OCCURRED(connect(socket_ids[index], address, addrlen))){
+			socket_print_error(stderr, ERROR_CODE, "Socket connect: ", "\n");
+			return ERROR_CODE;
+		}
+		if(verbose){
+			print_mark(index);
+		}
+	}
+	return EOK;
+}
+
+int sockets_sendto(int verbose, int * socket_ids, int sockets, struct sockaddr * address, socklen_t addrlen, char * data, int size, int messages){
+	ERROR_DECLARE;
+
+	int index;
+	int message;
+
+	if(verbose){
+		printf("\tSendto\t");
+	}
+	fflush(stdout);
+	for(index = 0; index < sockets; ++ index){
+		for(message = 0; message < messages; ++ message){
+			if(ERROR_OCCURRED(sendto(socket_ids[index], data, size, 0, address, addrlen))){
+				printf("Socket %d (%d), message %d error:\n", index, socket_ids[index], message);
+				socket_print_error(stderr, ERROR_CODE, "Socket send: ", "\n");
+				return ERROR_CODE;
+			}
+		}
+		if(verbose){
+			print_mark(index);
+		}
+	}
+	return EOK;
+}
+
+int sockets_recvfrom(int verbose, int * socket_ids, int sockets, struct sockaddr * address, socklen_t * addrlen, char * data, int size, int messages){
+	int value;
+	int index;
+	int message;
+
+	if(verbose){
+		printf("\tRecvfrom\t");
+	}
+	fflush(stdout);
+	for(index = 0; index < sockets; ++ index){
+		for(message = 0; message < messages; ++ message){
+			value = recvfrom(socket_ids[index], data, size, 0, address, addrlen);
+			if(value < 0){
+				printf("Socket %d (%d), message %d error:\n", index, socket_ids[index], message);
+				socket_print_error(stderr, value, "Socket receive: ", "\n");
+				return value;
+			}
+		}
+		if(verbose){
+			print_mark(index);
+		}
+	}
+	return EOK;
+}
+
+int sockets_sendto_recvfrom(int verbose, int * socket_ids, int sockets, struct sockaddr * address, socklen_t * addrlen, char * data, int size, int messages){
+	ERROR_DECLARE;
+
+	int value;
+	int index;
+	int message;
+
+	if(verbose){
+		printf("\tSendto and recvfrom\t");
+	}
+	fflush(stdout);
+	for(index = 0; index < sockets; ++ index){
+		for(message = 0; message < messages; ++ message){
+			if(ERROR_OCCURRED(sendto(socket_ids[index], data, size, 0, address, * addrlen))){
+				printf("Socket %d (%d), message %d error:\n", index, socket_ids[index], message);
+				socket_print_error(stderr, ERROR_CODE, "Socket send: ", "\n");
+				return ERROR_CODE;
+			}
+			value = recvfrom(socket_ids[index], data, size, 0, address, addrlen);
+			if(value < 0){
+				printf("Socket %d (%d), message %d error:\n", index, socket_ids[index], message);
+				socket_print_error(stderr, value, "Socket receive: ", "\n");
+				return value;
+			}
+		}
+		if(verbose){
+			print_mark(index);
+		}
+	}
+	return EOK;
+}
+
+void print_mark(int index){
+	if((index + 1) % 10){
+		printf("*");
+	}else{
+		printf("|");
+	}
+	fflush(stdout);
+}
+
+/** @}
+ */
Index: uspace/app/nettest1/nettest.h
===================================================================
--- uspace/app/nettest1/nettest.h	(revision 849ed54afbef3ad0ec3af831e93a1353f9eaaf0f)
+++ uspace/app/nettest1/nettest.h	(revision 849ed54afbef3ad0ec3af831e93a1353f9eaaf0f)
@@ -0,0 +1,126 @@
+/*
+ * 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 nettest
+ *  @{
+ */
+
+/** @file
+ *  Networking test support functions.
+ */
+
+#ifndef __NET_TEST__
+#define __NET_TEST__
+
+#include <socket.h>
+
+/** Prints a mark.
+ *  If the index is a multiple of ten, a different mark is printed.
+ *  @param[in] index The index of the mark to be printed.
+ */
+extern void print_mark(int index);
+
+/** Creates new sockets.
+ *  @param[in] verbose A value indicating whether to print out verbose information.
+ *  @param[out] socket_ids A field to store the socket identifiers.
+ *  @param[in] sockets The number of sockets to create. Should be at most the size of the field.
+ *  @param[in] family The socket address family.
+ *  @param[in] type The socket type.
+ *  @returns EOK on success.
+ *  @returns Other error codes as defined for the socket() function.
+ */
+extern int sockets_create(int verbose, int * socket_ids, int sockets, int family, sock_type_t type);
+
+/** Closes sockets.
+ *  @param[in] verbose A value indicating whether to print out verbose information.
+ *  @param[in] socket_ids A field of stored socket identifiers.
+ *  @param[in] sockets The number of sockets in the field. Should be at most the size of the field.
+ *  @returns EOK on success.
+ *  @returns Other error codes as defined for the closesocket() function.
+ */
+extern int sockets_close(int verbose, int * socket_ids, int sockets);
+
+/** Connects sockets.
+ *  @param[in] verbose A value indicating whether to print out verbose information.
+ *  @param[in] socket_ids A field of stored socket identifiers.
+ *  @param[in] sockets The number of sockets in the field. Should be at most the size of the field.
+ *  @param[in] address The destination host address to connect to.
+ *  @param[in] addrlen The length of the destination address in bytes.
+ *  @returns EOK on success.
+ *  @returns Other error codes as defined for the connect() function.
+ */
+extern int sockets_connect(int verbose, int * socket_ids, int sockets, struct sockaddr * address, socklen_t addrlen);
+
+/** Sends data via sockets.
+ *  @param[in] verbose A value indicating whether to print out verbose information.
+ *  @param[in] socket_ids A field of stored socket identifiers.
+ *  @param[in] sockets The number of sockets in the field. Should be at most the size of the field.
+ *  @param[in] address The destination host address to send data to.
+ *  @param[in] addrlen The length of the destination address in bytes.
+ *  @param[in] data The data to be sent.
+ *  @param[in] size The data size in bytes.
+ *  @param[in] messages The number of datagrams per socket to be sent.
+ *  @returns EOK on success.
+ *  @returns Other error codes as defined for the sendto() function.
+ */
+extern int sockets_sendto(int verbose, int * socket_ids, int sockets, struct sockaddr * address, socklen_t addrlen, char * data, int size, int messages);
+
+/** Receives data via sockets.
+ *  @param[in] verbose A value indicating whether to print out verbose information.
+ *  @param[in] socket_ids A field of stored socket identifiers.
+ *  @param[in] sockets The number of sockets in the field. Should be at most the size of the field.
+ *  @param[in] address The source host address of received datagrams.
+ *  @param[in,out] addrlen The maximum length of the source address in bytes. The actual size of the source address is set instead.
+ *  @param[out] data The received data.
+ *  @param[in] size The maximum data size in bytes.
+ *  @param[in] messages The number of datagrams per socket to be received.
+ *  @returns EOK on success.
+ *  @returns Other error codes as defined for the recvfrom() function.
+ */
+extern int sockets_recvfrom(int verbose, int * socket_ids, int sockets, struct sockaddr * address, socklen_t * addrlen, char * data, int size, int messages);
+
+/** Sends and receives data via sockets.
+ *  Each datagram is sent and a reply read consequently.
+ *  The next datagram is sent after the reply is received.
+ *  @param[in] verbose A value indicating whether to print out verbose information.
+ *  @param[in] socket_ids A field of stored socket identifiers.
+ *  @param[in] sockets The number of sockets in the field. Should be at most the size of the field.
+ *  @param[in,out] address The destination host address to send data to. The source host address of received datagrams is set instead.
+ *  @param[in] addrlen The length of the destination address in bytes.
+ *  @param[in,out] data The data to be sent. The received data are set instead.
+ *  @param[in] size The data size in bytes.
+ *  @param[in] messages The number of datagrams per socket to be received.
+ *  @returns EOK on success.
+ *  @returns Other error codes as defined for the recvfrom() function.
+ */
+extern int sockets_sendto_recvfrom(int verbose, int * socket_ids, int sockets, struct sockaddr * address, socklen_t * addrlen, char * data, int size, int messages);
+
+#endif
+
+/** @}
+ */
Index: uspace/app/nettest1/nettest1.c
===================================================================
--- uspace/app/nettest1/nettest1.c	(revision 849ed54afbef3ad0ec3af831e93a1353f9eaaf0f)
+++ uspace/app/nettest1/nettest1.c	(revision 849ed54afbef3ad0ec3af831e93a1353f9eaaf0f)
@@ -0,0 +1,424 @@
+/*
+ * 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 nettest
+ *  @{
+ */
+
+/** @file
+ *  Networking test 1 application - sockets.
+ */
+
+#include <malloc.h>
+#include <stdio.h>
+#include <str.h>
+#include <task.h>
+#include <time.h>
+
+#include <in.h>
+#include <in6.h>
+#include <inet.h>
+#include <socket.h>
+#include <net_err.h>
+
+#include "nettest.h"
+#include "parse.h"
+#include "print_error.h"
+
+/** Echo module name.
+ */
+#define NAME	"Nettest1"
+
+/** Packet data pattern.
+ */
+#define NETTEST1_TEXT	"Networking test 1 - sockets"
+
+/** Module entry point.
+ *  Starts testing.
+ *  @param[in] argc The number of command line parameters.
+ *  @param[in] argv The command line parameters.
+ *  @returns EOK on success.
+ */
+int main(int argc, char * argv[]);
+
+/** Prints the application help.
+ */
+void nettest1_print_help(void);
+
+/** Refreshes the data.
+ *  Fills the data block with the NETTEST1_TEXT pattern.
+ *  @param[out] data The data block.
+ *  @param[in] size The data block size in bytes.
+ */
+void nettest1_refresh_data(char * data, size_t size);
+
+int main(int argc, char * argv[]){
+	ERROR_DECLARE;
+
+	size_t size			= 27;
+	int verbose			= 0;
+	sock_type_t type	= SOCK_DGRAM;
+	int sockets			= 10;
+	int messages		= 10;
+	int family			= PF_INET;
+	uint16_t port		= 7;
+
+	socklen_t max_length				= sizeof(struct sockaddr_in6);
+	uint8_t address_data[max_length];
+	struct sockaddr * address			= (struct sockaddr *) address_data;
+	struct sockaddr_in * address_in		= (struct sockaddr_in *) address;
+	struct sockaddr_in6 * address_in6	= (struct sockaddr_in6 *) address;
+	socklen_t addrlen;
+//	char address_string[INET6_ADDRSTRLEN];
+	uint8_t * address_start;
+
+	int * socket_ids;
+	char * data;
+	int value;
+	int index;
+	struct timeval time_before;
+	struct timeval time_after;
+
+	// print the program label
+	printf("Task %d - ", task_get_id());
+	printf("%s\n", NAME);
+
+	// parse the command line arguments
+	// stop before the last argument if it does not start with the minus sign ('-')
+	for(index = 1; (index < argc - 1) || ((index == argc - 1) && (argv[index][0] == '-')); ++ index){
+		// options should start with the minus sign ('-')
+		if(argv[index][0] == '-'){
+			switch(argv[index][1]){
+				// short options with only one letter
+				case 'f':
+					ERROR_PROPAGATE(parse_parameter_name_int(argc, argv, &index, &family, "protocol family", 0, parse_protocol_family));
+					break;
+				case 'h':
+					nettest1_print_help();
+					return EOK;
+					break;
+				case 'm':
+					ERROR_PROPAGATE(parse_parameter_int(argc, argv, &index, &messages, "message count", 0));
+					break;
+				case 'n':
+					ERROR_PROPAGATE(parse_parameter_int(argc, argv, &index, &sockets, "socket count", 0));
+					break;
+				case 'p':
+					ERROR_PROPAGATE(parse_parameter_int(argc, argv, &index, &value, "port number", 0));
+					port = (uint16_t) value;
+					break;
+				case 's':
+					ERROR_PROPAGATE(parse_parameter_int(argc, argv, &index, &value, "packet size", 0));
+					size = (value >= 0) ? (size_t) value : 0;
+					break;
+				case 't':
+					ERROR_PROPAGATE(parse_parameter_name_int(argc, argv, &index, &value, "socket type", 0, parse_socket_type));
+					type = (sock_type_t) value;
+					break;
+				case 'v':
+					verbose = 1;
+					break;
+				// long options with the double minus sign ('-')
+				case '-':
+					if(str_lcmp(argv[index] + 2, "family=", 7) == 0){
+						ERROR_PROPAGATE(parse_parameter_name_int(argc, argv, &index, &family, "protocol family", 9, parse_protocol_family));
+					}else if(str_lcmp(argv[index] + 2, "help", 5) == 0){
+						nettest1_print_help();
+						return EOK;
+					}else if(str_lcmp(argv[index] + 2, "messages=", 6) == 0){
+						ERROR_PROPAGATE(parse_parameter_int(argc, argv, &index, &messages, "message count", 8));
+					}else if(str_lcmp(argv[index] + 2, "sockets=", 6) == 0){
+						ERROR_PROPAGATE(parse_parameter_int(argc, argv, &index, &sockets, "socket count", 8));
+					}else if(str_lcmp(argv[index] + 2, "port=", 5) == 0){
+						ERROR_PROPAGATE(parse_parameter_int(argc, argv, &index, &value, "port number", 7));
+						port = (uint16_t) value;
+					}else if(str_lcmp(argv[index] + 2, "type=", 5) == 0){
+						ERROR_PROPAGATE(parse_parameter_name_int(argc, argv, &index, &value, "socket type", 7, parse_socket_type));
+						type = (sock_type_t) value;
+					}else if(str_lcmp(argv[index] + 2, "verbose", 8) == 0){
+						verbose = 1;
+					}else{
+						print_unrecognized(index, argv[index] + 2);
+						nettest1_print_help();
+						return EINVAL;
+					}
+					break;
+				default:
+					print_unrecognized(index, argv[index] + 1);
+					nettest1_print_help();
+					return EINVAL;
+			}
+		}else{
+			print_unrecognized(index, argv[index]);
+			nettest1_print_help();
+			return EINVAL;
+		}
+	}
+
+	// if not before the last argument containing the address
+	if(index >= argc){
+		printf("Command line error: missing address\n");
+		nettest1_print_help();
+		return EINVAL;
+	}
+
+	// prepare the address buffer
+	bzero(address_data, max_length);
+	switch(family){
+		case PF_INET:
+			address_in->sin_family = AF_INET;
+			address_in->sin_port = htons(port);
+			address_start = (uint8_t *) &address_in->sin_addr.s_addr;
+			addrlen = sizeof(struct sockaddr_in);
+			break;
+		case PF_INET6:
+			address_in6->sin6_family = AF_INET6;
+			address_in6->sin6_port = htons(port);
+			address_start = (uint8_t *) &address_in6->sin6_addr.s6_addr;
+			addrlen = sizeof(struct sockaddr_in6);
+			break;
+		default:
+			fprintf(stderr, "Address family is not supported\n");
+			return EAFNOSUPPORT;
+	}
+
+	// parse the last argument which should contain the address
+	if(ERROR_OCCURRED(inet_pton(family, argv[argc - 1], address_start))){
+		fprintf(stderr, "Address parse error %d\n", ERROR_CODE);
+		return ERROR_CODE;
+	}
+
+	// check the buffer size
+	if(size <= 0){
+		fprintf(stderr, "Data buffer size too small (%d). Using 1024 bytes instead.\n", size);
+		size = 1024;
+	}
+
+	// prepare the buffer
+	// size plus the terminating null (\0)
+	data = (char *) malloc(size + 1);
+	if(! data){
+		fprintf(stderr, "Failed to allocate data buffer.\n");
+		return ENOMEM;
+	}
+	nettest1_refresh_data(data, size);
+
+	// check the socket count
+	if(sockets <= 0){
+		fprintf(stderr, "Socket count too small (%d). Using 2 instead.\n", sockets);
+		sockets = 2;
+	}
+
+	// prepare the socket buffer
+	// count plus the terminating null (\0)
+	socket_ids = (int *) malloc(sizeof(int) * (sockets + 1));
+	if(! socket_ids){
+		fprintf(stderr, "Failed to allocate receive buffer.\n");
+		return ENOMEM;
+	}
+	socket_ids[sockets] = NULL;
+
+	if(verbose){
+		printf("Starting tests\n");
+	}
+
+	if(verbose){
+		printf("1 socket, 1 message\n");
+	}
+
+	if(ERROR_OCCURRED(gettimeofday(&time_before, NULL))){
+		fprintf(stderr, "Get time of day error %d\n", ERROR_CODE);
+		return ERROR_CODE;
+	}
+
+	ERROR_PROPAGATE(sockets_create(verbose, socket_ids, 1, family, type));
+	ERROR_PROPAGATE(sockets_close(verbose, socket_ids, 1));
+	if(verbose){
+		printf("\tOK\n");
+	}
+
+	ERROR_PROPAGATE(sockets_create(verbose, socket_ids, 1, family, type));
+	if(type == SOCK_STREAM){
+		ERROR_PROPAGATE(sockets_connect(verbose, socket_ids, 1, address, addrlen));
+	}
+	ERROR_PROPAGATE(sockets_sendto_recvfrom(verbose, socket_ids, 1, address, &addrlen, data, size, 1));
+	ERROR_PROPAGATE(sockets_close(verbose, socket_ids, 1));
+	if(verbose){
+		printf("\tOK\n");
+	}
+
+	ERROR_PROPAGATE(sockets_create(verbose, socket_ids, 1, family, type));
+	if(type == SOCK_STREAM){
+		ERROR_PROPAGATE(sockets_connect(verbose, socket_ids, 1, address, addrlen));
+	}
+	ERROR_PROPAGATE(sockets_sendto(verbose, socket_ids, 1, address, addrlen, data, size, 1));
+	ERROR_PROPAGATE(sockets_recvfrom(verbose, socket_ids, 1, address, &addrlen, data, size, 1));
+	ERROR_PROPAGATE(sockets_close(verbose, socket_ids, 1));
+	if(verbose){
+		printf("\tOK\n");
+	}
+
+	if(verbose){
+		printf("1 socket, %d messages\n", messages);
+	}
+
+	ERROR_PROPAGATE(sockets_create(verbose, socket_ids, 1, family, type));
+	if(type == SOCK_STREAM){
+		ERROR_PROPAGATE(sockets_connect(verbose, socket_ids, 1, address, addrlen));
+	}
+	ERROR_PROPAGATE(sockets_sendto_recvfrom(verbose, socket_ids, 1, address, &addrlen, data, size, messages));
+	ERROR_PROPAGATE(sockets_close(verbose, socket_ids, 1));
+	if(verbose){
+		printf("\tOK\n");
+	}
+
+	ERROR_PROPAGATE(sockets_create(verbose, socket_ids, 1, family, type));
+	if(type == SOCK_STREAM){
+		ERROR_PROPAGATE(sockets_connect(verbose, socket_ids, 1, address, addrlen));
+	}
+	ERROR_PROPAGATE(sockets_sendto(verbose, socket_ids, 1, address, addrlen, data, size, messages));
+	ERROR_PROPAGATE(sockets_recvfrom(verbose, socket_ids, 1, address, &addrlen, data, size, messages));
+	ERROR_PROPAGATE(sockets_close(verbose, socket_ids, 1));
+	if(verbose){
+		printf("\tOK\n");
+	}
+
+	if(verbose){
+		printf("%d sockets, 1 message\n", sockets);
+	}
+
+	ERROR_PROPAGATE(sockets_create(verbose, socket_ids, sockets, family, type));
+	ERROR_PROPAGATE(sockets_close(verbose, socket_ids, sockets));
+	if(verbose){
+		printf("\tOK\n");
+	}
+
+	ERROR_PROPAGATE(sockets_create(verbose, socket_ids, sockets, family, type));
+	if(type == SOCK_STREAM){
+		ERROR_PROPAGATE(sockets_connect(verbose, socket_ids, sockets, address, addrlen));
+	}
+	ERROR_PROPAGATE(sockets_sendto_recvfrom(verbose, socket_ids, sockets, address, &addrlen, data, size, 1));
+	ERROR_PROPAGATE(sockets_close(verbose, socket_ids, sockets));
+	if(verbose){
+		printf("\tOK\n");
+	}
+
+	ERROR_PROPAGATE(sockets_create(verbose, socket_ids, sockets, family, type));
+	if(type == SOCK_STREAM){
+		ERROR_PROPAGATE(sockets_connect(verbose, socket_ids, sockets, address, addrlen));
+	}
+	ERROR_PROPAGATE(sockets_sendto(verbose, socket_ids, sockets, address, addrlen, data, size, 1));
+	ERROR_PROPAGATE(sockets_recvfrom(verbose, socket_ids, sockets, address, &addrlen, data, size, 1));
+	ERROR_PROPAGATE(sockets_close(verbose, socket_ids, sockets));
+	if(verbose){
+		printf("\tOK\n");
+	}
+
+	if(verbose){
+		printf("%d sockets, %d messages\n", sockets, messages);
+	}
+
+	ERROR_PROPAGATE(sockets_create(verbose, socket_ids, sockets, family, type));
+	if(type == SOCK_STREAM){
+		ERROR_PROPAGATE(sockets_connect(verbose, socket_ids, sockets, address, addrlen));
+	}
+	ERROR_PROPAGATE(sockets_sendto_recvfrom(verbose, socket_ids, sockets, address, &addrlen, data, size, messages));
+	ERROR_PROPAGATE(sockets_close(verbose, socket_ids, sockets));
+	if(verbose){
+		printf("\tOK\n");
+	}
+
+	ERROR_PROPAGATE(sockets_create(verbose, socket_ids, sockets, family, type));
+	if(type == SOCK_STREAM){
+		ERROR_PROPAGATE(sockets_connect(verbose, socket_ids, sockets, address, addrlen));
+	}
+	ERROR_PROPAGATE(sockets_sendto(verbose, socket_ids, sockets, address, addrlen, data, size, messages));
+	ERROR_PROPAGATE(sockets_recvfrom(verbose, socket_ids, sockets, address, &addrlen, data, size, messages));
+	ERROR_PROPAGATE(sockets_close(verbose, socket_ids, sockets));
+
+	if(ERROR_OCCURRED(gettimeofday(&time_after, NULL))){
+		fprintf(stderr, "Get time of day error %d\n", ERROR_CODE);
+		return ERROR_CODE;
+	}
+
+	if(verbose){
+		printf("\tOK\n");
+	}
+
+	printf("Tested in %d microseconds\n", tv_sub(&time_after, &time_before));
+
+	if(verbose){
+		printf("Exiting\n");
+	}
+
+	return EOK;
+}
+
+void nettest1_print_help(void){
+	printf(
+		"Network Networking test 1 aplication - sockets\n" \
+		"Usage: echo [options] numeric_address\n" \
+		"Where options are:\n" \
+		"-f protocol_family | --family=protocol_family\n" \
+		"\tThe listenning socket protocol family. Only the PF_INET and PF_INET6 are supported.\n"
+		"\n" \
+		"-h | --help\n" \
+		"\tShow this application help.\n"
+		"\n" \
+		"-m count | --messages=count\n" \
+		"\tThe number of messages to send and receive per socket. The default is 10.\n" \
+		"\n" \
+		"-n sockets | --sockets=count\n" \
+		"\tThe number of sockets to use. The default is 10.\n" \
+		"\n" \
+		"-p port_number | --port=port_number\n" \
+		"\tThe port number the application should send messages to. The default is 7.\n" \
+		"\n" \
+		"-s packet_size | --size=packet_size\n" \
+		"\tThe packet data size the application sends. The default is 28 bytes.\n" \
+		"\n" \
+		"-v | --verbose\n" \
+		"\tShow all output messages.\n"
+	);
+}
+
+void nettest1_refresh_data(char * data, size_t size){
+	size_t length;
+
+	// fill the data
+	length = 0;
+	while(size > length + sizeof(NETTEST1_TEXT) - 1){
+		memcpy(data + length, NETTEST1_TEXT, sizeof(NETTEST1_TEXT) - 1);
+		length += sizeof(NETTEST1_TEXT) - 1;
+	}
+	memcpy(data + length, NETTEST1_TEXT, size - length);
+	data[size] = '\0';
+}
+
+/** @}
+ */
Index: uspace/app/nettest1/parse.c
===================================================================
--- uspace/app/nettest1/parse.c	(revision 849ed54afbef3ad0ec3af831e93a1353f9eaaf0f)
+++ uspace/app/nettest1/parse.c	(revision 849ed54afbef3ad0ec3af831e93a1353f9eaaf0f)
@@ -0,0 +1,1 @@
+../netecho/parse.c
Index: uspace/app/nettest1/parse.h
===================================================================
--- uspace/app/nettest1/parse.h	(revision 849ed54afbef3ad0ec3af831e93a1353f9eaaf0f)
+++ uspace/app/nettest1/parse.h	(revision 849ed54afbef3ad0ec3af831e93a1353f9eaaf0f)
@@ -0,0 +1,1 @@
+../netecho/parse.h
Index: uspace/app/nettest1/print_error.c
===================================================================
--- uspace/app/nettest1/print_error.c	(revision 849ed54afbef3ad0ec3af831e93a1353f9eaaf0f)
+++ uspace/app/nettest1/print_error.c	(revision 849ed54afbef3ad0ec3af831e93a1353f9eaaf0f)
@@ -0,0 +1,1 @@
+../netecho/print_error.c
Index: uspace/app/nettest1/print_error.h
===================================================================
--- uspace/app/nettest1/print_error.h	(revision 849ed54afbef3ad0ec3af831e93a1353f9eaaf0f)
+++ uspace/app/nettest1/print_error.h	(revision 849ed54afbef3ad0ec3af831e93a1353f9eaaf0f)
@@ -0,0 +1,1 @@
+../netecho/print_error.h
Index: uspace/app/nettest2/Makefile
===================================================================
--- uspace/app/nettest2/Makefile	(revision 849ed54afbef3ad0ec3af831e93a1353f9eaaf0f)
+++ uspace/app/nettest2/Makefile	(revision 849ed54afbef3ad0ec3af831e93a1353f9eaaf0f)
@@ -0,0 +1,41 @@
+#
+# Copyright (c) 2005 Martin Decky
+# Copyright (c) 2007 Jakub Jermar
+# 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.
+#
+
+USPACE_PREFIX = ../..
+LIBS = $(LIBSOCKET_PREFIX)/libsocket.a
+EXTRA_CFLAGS = -I$(LIBSOCKET_PREFIX)/include
+BINARY = nettest2
+
+SOURCES = \
+	nettest2.c \
+	nettest.c \
+	parse.c \
+	print_error.c
+
+include $(USPACE_PREFIX)/Makefile.common
Index: uspace/app/nettest2/nettest.c
===================================================================
--- uspace/app/nettest2/nettest.c	(revision 849ed54afbef3ad0ec3af831e93a1353f9eaaf0f)
+++ uspace/app/nettest2/nettest.c	(revision 849ed54afbef3ad0ec3af831e93a1353f9eaaf0f)
@@ -0,0 +1,1 @@
+../nettest1/nettest.c
Index: uspace/app/nettest2/nettest.h
===================================================================
--- uspace/app/nettest2/nettest.h	(revision 849ed54afbef3ad0ec3af831e93a1353f9eaaf0f)
+++ uspace/app/nettest2/nettest.h	(revision 849ed54afbef3ad0ec3af831e93a1353f9eaaf0f)
@@ -0,0 +1,1 @@
+../nettest1/nettest.h
Index: uspace/app/nettest2/nettest2.c
===================================================================
--- uspace/app/nettest2/nettest2.c	(revision 849ed54afbef3ad0ec3af831e93a1353f9eaaf0f)
+++ uspace/app/nettest2/nettest2.c	(revision 849ed54afbef3ad0ec3af831e93a1353f9eaaf0f)
@@ -0,0 +1,347 @@
+/*
+ * 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 nettest
+ *  @{
+ */
+
+/** @file
+ *  Networking test 2 application - transfer.
+ */
+
+#include <malloc.h>
+#include <stdio.h>
+#include <str.h>
+#include <task.h>
+#include <time.h>
+
+#include <in.h>
+#include <in6.h>
+#include <inet.h>
+#include <socket.h>
+#include <net_err.h>
+
+#include "nettest.h"
+#include "parse.h"
+#include "print_error.h"
+
+/** Echo module name.
+ */
+#define NAME	"Nettest2"
+
+/** Packet data pattern.
+ */
+#define NETTEST2_TEXT	"Networking test 2 - transfer"
+
+/** Module entry point.
+ *  Starts testing.
+ *  @param[in] argc The number of command line parameters.
+ *  @param[in] argv The command line parameters.
+ *  @returns EOK on success.
+ */
+int main(int argc, char * argv[]);
+
+/** Prints the application help.
+ */
+void nettest2_print_help(void);
+
+/** Refreshes the data.
+ *  Fills the data block with the NETTEST1_TEXT pattern.
+ *  @param[out] data The data block.
+ *  @param[in] size The data block size in bytes.
+ */
+void nettest2_refresh_data(char * data, size_t size);
+
+int main(int argc, char * argv[]){
+	ERROR_DECLARE;
+
+	size_t size			= 28;
+	int verbose			= 0;
+	sock_type_t type	= SOCK_DGRAM;
+	int sockets			= 10;
+	int messages		= 10;
+	int family			= PF_INET;
+	uint16_t port		= 7;
+
+	socklen_t max_length				= sizeof(struct sockaddr_in6);
+	uint8_t address_data[max_length];
+	struct sockaddr * address			= (struct sockaddr *) address_data;
+	struct sockaddr_in * address_in		= (struct sockaddr_in *) address;
+	struct sockaddr_in6 * address_in6	= (struct sockaddr_in6 *) address;
+	socklen_t addrlen;
+//	char address_string[INET6_ADDRSTRLEN];
+	uint8_t * address_start;
+
+	int * socket_ids;
+	char * data;
+	int value;
+	int index;
+	struct timeval time_before;
+	struct timeval time_after;
+
+	printf("Task %d - ", task_get_id());
+	printf("%s\n", NAME);
+
+	// parse the command line arguments
+	// stop before the last argument if it does not start with the minus sign ('-')
+	for(index = 1; (index < argc - 1) || ((index == argc - 1) && (argv[index][0] == '-')); ++ index){
+		// options should start with the minus sign ('-')
+		if(argv[index][0] == '-'){
+			switch(argv[index][1]){
+				// short options with only one letter
+				case 'f':
+					ERROR_PROPAGATE(parse_parameter_name_int(argc, argv, &index, &family, "protocol family", 0, parse_protocol_family));
+					break;
+				case 'h':
+					nettest2_print_help();
+					return EOK;
+					break;
+				case 'm':
+					ERROR_PROPAGATE(parse_parameter_int(argc, argv, &index, &messages, "message count", 0));
+					break;
+				case 'n':
+					ERROR_PROPAGATE(parse_parameter_int(argc, argv, &index, &sockets, "socket count", 0));
+					break;
+				case 'p':
+					ERROR_PROPAGATE(parse_parameter_int(argc, argv, &index, &value, "port number", 0));
+					port = (uint16_t) value;
+					break;
+				case 's':
+					ERROR_PROPAGATE(parse_parameter_int(argc, argv, &index, &value, "packet size", 0));
+					size = (value >= 0) ? (size_t) value : 0;
+					break;
+				case 't':
+					ERROR_PROPAGATE(parse_parameter_name_int(argc, argv, &index, &value, "socket type", 0, parse_socket_type));
+					type = (sock_type_t) value;
+					break;
+				case 'v':
+					verbose = 1;
+					break;
+				// long options with the double minus sign ('-')
+				case '-':
+					if(str_lcmp(argv[index] + 2, "family=", 7) == 0){
+						ERROR_PROPAGATE(parse_parameter_name_int(argc, argv, &index, &family, "protocol family", 9, parse_protocol_family));
+					}else if(str_lcmp(argv[index] + 2, "help", 5) == 0){
+						nettest2_print_help();
+						return EOK;
+					}else if(str_lcmp(argv[index] + 2, "messages=", 6) == 0){
+						ERROR_PROPAGATE(parse_parameter_int(argc, argv, &index, &messages, "message count", 8));
+					}else if(str_lcmp(argv[index] + 2, "sockets=", 6) == 0){
+						ERROR_PROPAGATE(parse_parameter_int(argc, argv, &index, &sockets, "socket count", 8));
+					}else if(str_lcmp(argv[index] + 2, "port=", 5) == 0){
+						ERROR_PROPAGATE(parse_parameter_int(argc, argv, &index, &value, "port number", 7));
+						port = (uint16_t) value;
+					}else if(str_lcmp(argv[index] + 2, "type=", 5) == 0){
+						ERROR_PROPAGATE(parse_parameter_name_int(argc, argv, &index, &value, "socket type", 7, parse_socket_type));
+						type = (sock_type_t) value;
+					}else if(str_lcmp(argv[index] + 2, "verbose", 8) == 0){
+						verbose = 1;
+					}else{
+						print_unrecognized(index, argv[index] + 2);
+						nettest2_print_help();
+						return EINVAL;
+					}
+					break;
+				default:
+					print_unrecognized(index, argv[index] + 1);
+					nettest2_print_help();
+					return EINVAL;
+			}
+		}else{
+			print_unrecognized(index, argv[index]);
+			nettest2_print_help();
+			return EINVAL;
+		}
+	}
+
+	// if not before the last argument containing the address
+	if(index >= argc){
+		printf("Command line error: missing address\n");
+		nettest2_print_help();
+		return EINVAL;
+	}
+
+	// prepare the address buffer
+	bzero(address_data, max_length);
+	switch(family){
+		case PF_INET:
+			address_in->sin_family = AF_INET;
+			address_in->sin_port = htons(port);
+			address_start = (uint8_t *) &address_in->sin_addr.s_addr;
+			addrlen = sizeof(struct sockaddr_in);
+			break;
+		case PF_INET6:
+			address_in6->sin6_family = AF_INET6;
+			address_in6->sin6_port = htons(port);
+			address_start = (uint8_t *) &address_in6->sin6_addr.s6_addr;
+			addrlen = sizeof(struct sockaddr_in6);
+			break;
+		default:
+			fprintf(stderr, "Address family is not supported\n");
+			return EAFNOSUPPORT;
+	}
+
+	// parse the last argument which should contain the address
+	if(ERROR_OCCURRED(inet_pton(family, argv[argc - 1], address_start))){
+		fprintf(stderr, "Address parse error %d\n", ERROR_CODE);
+		return ERROR_CODE;
+	}
+
+	// check the buffer size
+	if(size <= 0){
+		fprintf(stderr, "Data buffer size too small (%d). Using 1024 bytes instead.\n", size);
+		size = 1024;
+	}
+
+	// prepare the buffer
+	// size plus terminating null (\0)
+	data = (char *) malloc(size + 1);
+	if(! data){
+		fprintf(stderr, "Failed to allocate data buffer.\n");
+		return ENOMEM;
+	}
+	nettest2_refresh_data(data, size);
+
+	// check the socket count
+	if(sockets <= 0){
+		fprintf(stderr, "Socket count too small (%d). Using 2 instead.\n", sockets);
+		sockets = 2;
+	}
+
+	// prepare the socket buffer
+	// count plus the terminating null (\0)
+	socket_ids = (int *) malloc(sizeof(int) * (sockets + 1));
+	if(! socket_ids){
+		fprintf(stderr, "Failed to allocate receive buffer.\n");
+		return ENOMEM;
+	}
+	socket_ids[sockets] = NULL;
+
+	if(verbose){
+		printf("Starting tests\n");
+	}
+
+	ERROR_PROPAGATE(sockets_create(verbose, socket_ids, sockets, family, type));
+
+	if(type == SOCK_STREAM){
+		ERROR_PROPAGATE(sockets_connect(verbose, socket_ids, sockets, address, addrlen));
+	}
+
+	if(verbose){
+		printf("\n");
+	}
+
+	if(ERROR_OCCURRED(gettimeofday(&time_before, NULL))){
+		fprintf(stderr, "Get time of day error %d\n", ERROR_CODE);
+		return ERROR_CODE;
+	}
+
+	ERROR_PROPAGATE(sockets_sendto_recvfrom(verbose, socket_ids, sockets, address, &addrlen, data, size, messages));
+
+	if(ERROR_OCCURRED(gettimeofday(&time_after, NULL))){
+		fprintf(stderr, "Get time of day error %d\n", ERROR_CODE);
+		return ERROR_CODE;
+	}
+
+	if(verbose){
+		printf("\tOK\n");
+	}
+
+	printf("sendto + recvfrom tested in %d microseconds\n", tv_sub(&time_after, &time_before));
+
+	if(ERROR_OCCURRED(gettimeofday(&time_before, NULL))){
+		fprintf(stderr, "Get time of day error %d\n", ERROR_CODE);
+		return ERROR_CODE;
+	}
+
+	ERROR_PROPAGATE(sockets_sendto(verbose, socket_ids, sockets, address, addrlen, data, size, messages));
+	ERROR_PROPAGATE(sockets_recvfrom(verbose, socket_ids, sockets, address, &addrlen, data, size, messages));
+
+	if(ERROR_OCCURRED(gettimeofday(&time_after, NULL))){
+		fprintf(stderr, "Get time of day error %d\n", ERROR_CODE);
+		return ERROR_CODE;
+	}
+
+	if(verbose){
+		printf("\tOK\n");
+	}
+
+	printf("sendto, recvfrom tested in %d microseconds\n", tv_sub(&time_after, &time_before));
+
+	ERROR_PROPAGATE(sockets_close(verbose, socket_ids, sockets));
+
+	if(verbose){
+		printf("\nExiting\n");
+	}
+
+	return EOK;
+}
+
+void nettest2_print_help(void){
+	printf(
+		"Network Networking test 2 aplication - UDP transfer\n" \
+		"Usage: echo [options] numeric_address\n" \
+		"Where options are:\n" \
+		"-f protocol_family | --family=protocol_family\n" \
+		"\tThe listenning socket protocol family. Only the PF_INET and PF_INET6 are supported.\n"
+		"\n" \
+		"-h | --help\n" \
+		"\tShow this application help.\n"
+		"\n" \
+		"-m count | --messages=count\n" \
+		"\tThe number of messages to send and receive per socket. The default is 10.\n" \
+		"\n" \
+		"-n sockets | --sockets=count\n" \
+		"\tThe number of sockets to use. The default is 10.\n" \
+		"\n" \
+		"-p port_number | --port=port_number\n" \
+		"\tThe port number the application should send messages to. The default is 7.\n" \
+		"\n" \
+		"-s packet_size | --size=packet_size\n" \
+		"\tThe packet data size the application sends. The default is 29 bytes.\n" \
+		"\n" \
+		"-v | --verbose\n" \
+		"\tShow all output messages.\n"
+	);
+}
+
+void nettest2_refresh_data(char * data, size_t size){
+	size_t length;
+
+	// fill the data
+	length = 0;
+	while(size > length + sizeof(NETTEST2_TEXT) - 1){
+		memcpy(data + length, NETTEST2_TEXT, sizeof(NETTEST2_TEXT) - 1);
+		length += sizeof(NETTEST2_TEXT) - 1;
+	}
+	memcpy(data + length, NETTEST2_TEXT, size - length);
+	data[size] = '\0';
+}
+
+/** @}
+ */
Index: uspace/app/nettest2/parse.c
===================================================================
--- uspace/app/nettest2/parse.c	(revision 849ed54afbef3ad0ec3af831e93a1353f9eaaf0f)
+++ uspace/app/nettest2/parse.c	(revision 849ed54afbef3ad0ec3af831e93a1353f9eaaf0f)
@@ -0,0 +1,1 @@
+../netecho/parse.c
Index: uspace/app/nettest2/parse.h
===================================================================
--- uspace/app/nettest2/parse.h	(revision 849ed54afbef3ad0ec3af831e93a1353f9eaaf0f)
+++ uspace/app/nettest2/parse.h	(revision 849ed54afbef3ad0ec3af831e93a1353f9eaaf0f)
@@ -0,0 +1,1 @@
+../netecho/parse.h
Index: uspace/app/nettest2/print_error.c
===================================================================
--- uspace/app/nettest2/print_error.c	(revision 849ed54afbef3ad0ec3af831e93a1353f9eaaf0f)
+++ uspace/app/nettest2/print_error.c	(revision 849ed54afbef3ad0ec3af831e93a1353f9eaaf0f)
@@ -0,0 +1,1 @@
+../netecho/print_error.c
Index: uspace/app/nettest2/print_error.h
===================================================================
--- uspace/app/nettest2/print_error.h	(revision 849ed54afbef3ad0ec3af831e93a1353f9eaaf0f)
+++ uspace/app/nettest2/print_error.h	(revision 849ed54afbef3ad0ec3af831e93a1353f9eaaf0f)
@@ -0,0 +1,1 @@
+../netecho/print_error.h
Index: uspace/app/ping/Makefile
===================================================================
--- uspace/app/ping/Makefile	(revision 849ed54afbef3ad0ec3af831e93a1353f9eaaf0f)
+++ uspace/app/ping/Makefile	(revision 849ed54afbef3ad0ec3af831e93a1353f9eaaf0f)
@@ -0,0 +1,40 @@
+#
+# Copyright (c) 2005 Martin Decky
+# Copyright (c) 2007 Jakub Jermar
+# 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.
+#
+
+USPACE_PREFIX = ../..
+LIBS = $(LIBSOCKET_PREFIX)/libsocket.a
+EXTRA_CFLAGS = -I$(LIBSOCKET_PREFIX)/include
+BINARY = ping
+
+SOURCES = \
+	ping.c \
+	parse.c \
+	print_error.c
+
+include $(USPACE_PREFIX)/Makefile.common
Index: uspace/app/ping/parse.c
===================================================================
--- uspace/app/ping/parse.c	(revision 849ed54afbef3ad0ec3af831e93a1353f9eaaf0f)
+++ uspace/app/ping/parse.c	(revision 849ed54afbef3ad0ec3af831e93a1353f9eaaf0f)
@@ -0,0 +1,1 @@
+../netecho/parse.c
Index: uspace/app/ping/parse.h
===================================================================
--- uspace/app/ping/parse.h	(revision 849ed54afbef3ad0ec3af831e93a1353f9eaaf0f)
+++ uspace/app/ping/parse.h	(revision 849ed54afbef3ad0ec3af831e93a1353f9eaaf0f)
@@ -0,0 +1,1 @@
+../netecho/parse.h
Index: uspace/app/ping/ping.c
===================================================================
--- uspace/app/ping/ping.c	(revision 849ed54afbef3ad0ec3af831e93a1353f9eaaf0f)
+++ uspace/app/ping/ping.c	(revision 849ed54afbef3ad0ec3af831e93a1353f9eaaf0f)
@@ -0,0 +1,301 @@
+/*
+ * 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 ping
+ *  @{
+ */
+
+/** @file
+ *  Ping application.
+ */
+
+#include <stdio.h>
+#include <str.h>
+#include <task.h>
+#include <time.h>
+#include <ipc/ipc.h>
+#include <ipc/services.h>
+
+#include <icmp_api.h>
+#include <in.h>
+#include <in6.h>
+#include <inet.h>
+#include <ip_codes.h>
+#include <socket_errno.h>
+#include <net_err.h>
+
+#include "parse.h"
+#include "print_error.h"
+
+/** Echo module name.
+ */
+#define NAME	"Ping"
+
+/** Module entry point.
+ *  Reads command line parameters and pings.
+ *  @param[in] argc The number of command line parameters.
+ *  @param[in] argv The command line parameters.
+ *  @returns EOK on success.
+ */
+int main(int argc, char * argv[]);
+
+/** Prints the application help.
+ */
+void ping_print_help(void);
+
+int main(int argc, char * argv[]){
+	ERROR_DECLARE;
+
+	size_t size			= 38;
+	int verbose			= 0;
+	int dont_fragment	= 0;
+	ip_ttl_t ttl		= 0;
+	ip_tos_t tos		= 0;
+	int count			= 3;
+	suseconds_t timeout	= 3000;
+	int family			= AF_INET;
+
+	socklen_t max_length				= sizeof(struct sockaddr_in6);
+	uint8_t address_data[max_length];
+	struct sockaddr * address			= (struct sockaddr *) address_data;
+	struct sockaddr_in * address_in		= (struct sockaddr_in *) address;
+	struct sockaddr_in6 * address_in6	= (struct sockaddr_in6 *) address;
+	socklen_t addrlen;
+	char address_string[INET6_ADDRSTRLEN];
+	uint8_t * address_start;
+	int icmp_phone;
+	struct timeval time_before;
+	struct timeval time_after;
+	int result;
+	int value;
+	int index;
+
+	// print the program label
+	printf("Task %d - ", task_get_id());
+	printf("%s\n", NAME);
+
+	// parse the command line arguments
+	// stop before the last argument if it does not start with the minus sign ('-')
+	for(index = 1; (index < argc - 1) || ((index == argc - 1) && (argv[index][0] == '-')); ++ index){
+		// options should start with the minus sign ('-')
+		if(argv[index][0] == '-'){
+			switch(argv[index][1]){
+				// short options with only one letter
+				case 'c':
+					ERROR_PROPAGATE(parse_parameter_int(argc, argv, &index, &count, "count", 0));
+					break;
+				case 'f':
+					ERROR_PROPAGATE(parse_parameter_name_int(argc, argv, &index, &family, "address family", 0, parse_address_family));
+					break;
+				case 'h':
+					ping_print_help();
+					return EOK;
+					break;
+				case 's':
+					ERROR_PROPAGATE(parse_parameter_int(argc, argv, &index, &value, "packet size", 0));
+					size = (value >= 0) ? (size_t) value : 0;
+					break;
+				case 't':
+					ERROR_PROPAGATE(parse_parameter_int(argc, argv, &index, &value, "timeout", 0));
+					timeout = (value >= 0) ? (suseconds_t) value : 0;
+					break;
+				case 'v':
+					verbose = 1;
+					break;
+				// long options with the double minus sign ('-')
+				case '-':
+					if(str_lcmp(argv[index] + 2, "count=", 6) == 0){
+						ERROR_PROPAGATE(parse_parameter_int(argc, argv, &index, &count, "received count", 8));
+					}else if(str_lcmp(argv[index] + 2, "dont_fragment", 13) == 0){
+						dont_fragment = 1;
+					}else if(str_lcmp(argv[index] + 2, "family=", 7) == 0){
+						ERROR_PROPAGATE(parse_parameter_name_int(argc, argv, &index, &family, "address family", 9, parse_address_family));
+					}else if(str_lcmp(argv[index] + 2, "help", 5) == 0){
+						ping_print_help();
+						return EOK;
+					}else if(str_lcmp(argv[index] + 2, "size=", 5) == 0){
+						ERROR_PROPAGATE(parse_parameter_int(argc, argv, &index, &value, "packet size", 7));
+						size = (value >= 0) ? (size_t) value : 0;
+					}else if(str_lcmp(argv[index] + 2, "timeout=", 8) == 0){
+						ERROR_PROPAGATE(parse_parameter_int(argc, argv, &index, &value, "timeout", 7));
+						timeout = (value >= 0) ? (suseconds_t) value : 0;
+					}else if(str_lcmp(argv[index] + 2, "tos=", 4) == 0){
+						ERROR_PROPAGATE(parse_parameter_int(argc, argv, &index, &value, "type of service", 7));
+						tos = (value >= 0) ? (ip_tos_t) value : 0;
+					}else if(str_lcmp(argv[index] + 2, "ttl=", 4) == 0){
+						ERROR_PROPAGATE(parse_parameter_int(argc, argv, &index, &value, "time to live", 7));
+						ttl = (value >= 0) ? (ip_ttl_t) value : 0;
+					}else if(str_lcmp(argv[index] + 2, "verbose", 8) == 0){
+						verbose = 1;
+					}else{
+						print_unrecognized(index, argv[index] + 2);
+						ping_print_help();
+						return EINVAL;
+					}
+					break;
+				default:
+					print_unrecognized(index, argv[index] + 1);
+					ping_print_help();
+					return EINVAL;
+			}
+		}else{
+			print_unrecognized(index, argv[index]);
+			ping_print_help();
+			return EINVAL;
+		}
+	}
+
+	// if not before the last argument containing the address
+	if(index >= argc){
+		printf("Command line error: missing address\n");
+		ping_print_help();
+		return EINVAL;
+	}
+
+	// prepare the address buffer
+	bzero(address_data, max_length);
+	switch(family){
+		case AF_INET:
+			address_in->sin_family = AF_INET;
+			address_start = (uint8_t *) &address_in->sin_addr.s_addr;
+			addrlen = sizeof(struct sockaddr_in);
+			break;
+		case AF_INET6:
+			address_in6->sin6_family = AF_INET6;
+			address_start = (uint8_t *) &address_in6->sin6_addr.s6_addr;
+			addrlen = sizeof(struct sockaddr_in6);
+			break;
+		default:
+			fprintf(stderr, "Address family is not supported\n");
+			return EAFNOSUPPORT;
+	}
+
+	// parse the last argument which should contain the address
+	if(ERROR_OCCURRED(inet_pton(family, argv[argc - 1], address_start))){
+		fprintf(stderr, "Address parse error %d\n", ERROR_CODE);
+		return ERROR_CODE;
+	}
+
+	// connect to the ICMP module
+	icmp_phone = icmp_connect_module(SERVICE_ICMP, ICMP_CONNECT_TIMEOUT);
+	if(icmp_phone < 0){
+		fprintf(stderr, "ICMP connect error %d\n", icmp_phone);
+		return icmp_phone;
+	}
+
+	// print the ping header
+	printf("PING %d bytes of data\n", size);
+	if(ERROR_OCCURRED(inet_ntop(address->sa_family, address_start, address_string, sizeof(address_string)))){
+		fprintf(stderr, "Address error %d\n", ERROR_CODE);
+	}else{
+		printf("Address %s:\n", address_string);
+	}
+
+	// do count times
+	while(count > 0){
+
+		// get the starting time
+		if(ERROR_OCCURRED(gettimeofday(&time_before, NULL))){
+			fprintf(stderr, "Get time of day error %d\n", ERROR_CODE);
+			// release the ICMP phone
+			ipc_hangup(icmp_phone);
+			return ERROR_CODE;
+		}
+
+		// request the ping
+		result = icmp_echo_msg(icmp_phone, size, timeout, ttl, tos, dont_fragment, address, addrlen);
+
+		// get the ending time
+		if(ERROR_OCCURRED(gettimeofday(&time_after, NULL))){
+			fprintf(stderr, "Get time of day error %d\n", ERROR_CODE);
+			// release the ICMP phone
+			ipc_hangup(icmp_phone);
+			return ERROR_CODE;
+		}
+
+		// print the result
+		switch(result){
+			case ICMP_ECHO:
+				printf("Ping round trip time %d miliseconds\n", tv_sub(&time_after, &time_before) / 1000);
+				break;
+			case ETIMEOUT:
+				printf("Timed out.\n");
+				break;
+			default:
+				print_error(stdout, result, NULL, "\n");
+		}
+		-- count;
+	}
+
+	if(verbose){
+		printf("Exiting\n");
+	}
+
+	// release the ICMP phone
+	ipc_hangup(icmp_phone);
+
+	return EOK;
+}
+
+void ping_print_help(void){
+	printf(
+		"Network Ping aplication\n" \
+		"Usage: ping [options] numeric_address\n" \
+		"Where options are:\n" \
+		"\n" \
+		"-c request_count | --count=request_count\n" \
+		"\tThe number of packets the application sends. The default is three (3).\n" \
+		"\n" \
+		"--dont_fragment\n" \
+		"\tDisable packet fragmentation.\n"
+		"\n" \
+		"-f address_family | --family=address_family\n" \
+		"\tThe given address family. Only the AF_INET and AF_INET6 are supported.\n"
+		"\n" \
+		"-h | --help\n" \
+		"\tShow this application help.\n"
+		"\n" \
+		"-s packet_size | --size=packet_size\n" \
+		"\tThe packet data size the application sends. The default is 38 bytes.\n" \
+		"\n" \
+		"-t timeout | --timeout=timeout\n" \
+		"\tThe number of miliseconds the application waits for a reply. The default is three thousands (3 000).\n" \
+		"\n" \
+		"--tos=tos\n" \
+		"\tThe type of service to be used.\n" \
+		"\n" \
+		"--ttl=ttl\n" \
+		"\tThe time to live to be used.\n" \
+		"\n" \
+		"-v | --verbose\n" \
+		"\tShow all output messages.\n"
+	);
+}
+
+/** @}
+ */
Index: uspace/app/ping/print_error.c
===================================================================
--- uspace/app/ping/print_error.c	(revision 849ed54afbef3ad0ec3af831e93a1353f9eaaf0f)
+++ uspace/app/ping/print_error.c	(revision 849ed54afbef3ad0ec3af831e93a1353f9eaaf0f)
@@ -0,0 +1,1 @@
+../netecho/print_error.c
Index: uspace/app/ping/print_error.h
===================================================================
--- uspace/app/ping/print_error.h	(revision 849ed54afbef3ad0ec3af831e93a1353f9eaaf0f)
+++ uspace/app/ping/print_error.h	(revision 849ed54afbef3ad0ec3af831e93a1353f9eaaf0f)
@@ -0,0 +1,1 @@
+../netecho/print_error.h
