source: mainline/uspace/app/nettest1/nettest1.c@ 02a09ed

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

add basic infrastructure for IPv6 (inactive)
make inet_addr_t a universal address type

  • Property mode set to 100644
File size: 10.6 KB
RevLine 
[21580dd]1/*
2 * Copyright (c) 2009 Lukas Mejdrech
3 * All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
7 * are met:
8 *
9 * - Redistributions of source code must retain the above copyright
10 * notice, this list of conditions and the following disclaimer.
11 * - Redistributions in binary form must reproduce the above copyright
12 * notice, this list of conditions and the following disclaimer in the
13 * documentation and/or other materials provided with the distribution.
14 * - The name of the author may not be used to endorse or promote products
15 * derived from this software without specific prior written permission.
16 *
17 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
18 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
19 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
20 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
21 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
22 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
23 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
24 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
25 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
26 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
27 */
28
29/** @addtogroup nettest
[3d459fc]30 * @{
[21580dd]31 */
32
33/** @file
[3d459fc]34 * Networking test 1 application - sockets.
[21580dd]35 */
36
[3d459fc]37#include "nettest.h"
38#include "print_error.h"
39
[21580dd]40#include <malloc.h>
41#include <stdio.h>
[d4d74dc]42#include <unistd.h>
[19f857a]43#include <str.h>
[21580dd]44#include <task.h>
45#include <time.h>
[2721a75]46#include <arg_parse.h>
[21580dd]47
[287d729]48#include <inet/dnsr.h>
[e4554d4]49#include <net/in.h>
50#include <net/in6.h>
51#include <net/inet.h>
[d9e2e0e]52#include <net/socket.h>
53#include <net/socket_parse.h>
[21580dd]54
[3d459fc]55/** Echo module name. */
[b5cf742a]56#define NAME "nettest1"
[21580dd]57
[3d459fc]58/** Packet data pattern. */
[b5cf742a]59#define NETTEST1_TEXT "Networking test 1 - sockets"
[21580dd]60
[02a09ed]61static uint16_t family = AF_INET;
[69e0d6d]62static sock_type_t type = SOCK_DGRAM;
63static size_t size = 27;
[02a09ed]64static bool verbose = false;
65static int sockets = 10;
66static int messages = 10;
67static uint16_t port = 7;
[0bbef9b]68
[69e0d6d]69static struct sockaddr *address;
70static socklen_t addrlen;
71
[02a09ed]72static char *data;
[0bbef9b]73
[3d459fc]74static void nettest1_print_help(void)
75{
76 printf(
[69e0d6d]77 "Network Networking test 1 aplication - sockets\n"
[287d729]78 "Usage: nettest1 [options] host\n"
[69e0d6d]79 "Where options are:\n"
80 "-f protocol_family | --family=protocol_family\n"
81 "\tThe listenning socket protocol family. Only the PF_INET and "
82 "PF_INET6 are supported.\n"
83 "\n"
84 "-h | --help\n"
85 "\tShow this application help.\n"
86 "\n"
87 "-m count | --messages=count\n"
88 "\tThe number of messages to send and receive per socket. The "
89 "default is 10.\n"
90 "\n"
91 "-n sockets | --sockets=count\n"
92 "\tThe number of sockets to use. The default is 10.\n"
93 "\n"
94 "-p port_number | --port=port_number\n"
95 "\tThe port number the application should send messages to. The "
96 "default is 7.\n"
97 "\n"
98 "-s packet_size | --size=packet_size\n"
99 "\tThe packet data size the application sends. The default is "
100 "28 bytes.\n"
101 "\n"
102 "-v | --verbose\n"
103 "\tShow all output messages.\n");
[3d459fc]104}
[21580dd]105
[69e0d6d]106/** Parse one command-line option.
[3d459fc]107 *
[69e0d6d]108 * @param argc Number of all command-line arguments.
109 * @param argv All command-line arguments.
110 * @param index Current argument index (in, out).
111 */
112static int nettest1_parse_opt(int argc, char *argv[], int *index)
113{
114 int value;
115 int rc;
[b5cf742a]116
[69e0d6d]117 switch (argv[*index][1]) {
118 /*
119 * Short options with only one letter
120 */
121 case 'f':
[b5cf742a]122 rc = arg_parse_name_int(argc, argv, index, &value, 0,
123 socket_parse_protocol_family);
[69e0d6d]124 if (rc != EOK)
125 return rc;
[b5cf742a]126
127 family = (uint16_t) value;
[69e0d6d]128 break;
129 case 'h':
130 nettest1_print_help();
131 return EOK;
132 case 'm':
133 rc = arg_parse_int(argc, argv, index, &messages, 0);
134 if (rc != EOK)
135 return rc;
[b5cf742a]136
[69e0d6d]137 break;
138 case 'n':
139 rc = arg_parse_int(argc, argv, index, &sockets, 0);
140 if (rc != EOK)
141 return rc;
[b5cf742a]142
[69e0d6d]143 break;
144 case 'p':
145 rc = arg_parse_int(argc, argv, index, &value, 0);
146 if (rc != EOK)
147 return rc;
[b5cf742a]148
[69e0d6d]149 port = (uint16_t) value;
150 break;
151 case 's':
152 rc = arg_parse_int(argc, argv, index, &value, 0);
153 if (rc != EOK)
154 return rc;
[b5cf742a]155
[69e0d6d]156 size = (value >= 0) ? (size_t) value : 0;
157 break;
158 case 't':
[b5cf742a]159 rc = arg_parse_name_int(argc, argv, index, &value, 0,
160 socket_parse_socket_type);
[69e0d6d]161 if (rc != EOK)
162 return rc;
[b5cf742a]163
[69e0d6d]164 type = (sock_type_t) value;
165 break;
166 case 'v':
167 verbose = 1;
168 break;
[b5cf742a]169
[69e0d6d]170 /*
171 * Long options with double dash ('-')
172 */
173 case '-':
174 if (str_lcmp(argv[*index] + 2, "family=", 7) == 0) {
[b5cf742a]175 rc = arg_parse_name_int(argc, argv, index, &value, 9,
[69e0d6d]176 socket_parse_protocol_family);
177 if (rc != EOK)
178 return rc;
[b5cf742a]179
180 family = (uint16_t) value;
[69e0d6d]181 } else if (str_lcmp(argv[*index] + 2, "help", 5) == 0) {
182 nettest1_print_help();
183 return EOK;
184 } else if (str_lcmp(argv[*index] + 2, "messages=", 6) == 0) {
185 rc = arg_parse_int(argc, argv, index, &messages, 8);
186 if (rc != EOK)
187 return rc;
188 } else if (str_lcmp(argv[*index] + 2, "sockets=", 6) == 0) {
189 rc = arg_parse_int(argc, argv, index, &sockets, 8);
190 if (rc != EOK)
191 return rc;
192 } else if (str_lcmp(argv[*index] + 2, "port=", 5) == 0) {
193 rc = arg_parse_int(argc, argv, index, &value, 7);
194 if (rc != EOK)
195 return rc;
[b5cf742a]196
[69e0d6d]197 port = (uint16_t) value;
198 } else if (str_lcmp(argv[*index] + 2, "type=", 5) == 0) {
199 rc = arg_parse_name_int(argc, argv, index, &value, 7,
200 socket_parse_socket_type);
201 if (rc != EOK)
202 return rc;
[b5cf742a]203
[69e0d6d]204 type = (sock_type_t) value;
205 } else if (str_lcmp(argv[*index] + 2, "verbose", 8) == 0) {
206 verbose = 1;
207 } else {
208 nettest1_print_help();
209 return EINVAL;
210 }
211 break;
212 default:
213 nettest1_print_help();
214 return EINVAL;
215 }
[b5cf742a]216
[69e0d6d]217 return EOK;
218}
219
220/** Fill buffer with the NETTEST1_TEXT pattern.
[3d459fc]221 *
[69e0d6d]222 * @param buffer Data buffer.
223 * @param size Buffer size in bytes.
[21580dd]224 */
[69e0d6d]225static void nettest1_fill_buffer(char *buffer, size_t size)
[3d459fc]226{
[b5cf742a]227 size_t length = 0;
[3d459fc]228 while (size > length + sizeof(NETTEST1_TEXT) - 1) {
[69e0d6d]229 memcpy(buffer + length, NETTEST1_TEXT,
230 sizeof(NETTEST1_TEXT) - 1);
[3d459fc]231 length += sizeof(NETTEST1_TEXT) - 1;
232 }
[b5cf742a]233
[69e0d6d]234 memcpy(buffer + length, NETTEST1_TEXT, size - length);
235 buffer[size] = '\0';
[3d459fc]236}
[21580dd]237
[0bbef9b]238static int nettest1_test(int *socket_ids, int nsockets, int nmessages)
239{
240 if (verbose)
241 printf("%d sockets, %d messages\n", nsockets, nmessages);
[b5cf742a]242
243 int rc = sockets_create(verbose, socket_ids, nsockets, family, type);
[0bbef9b]244 if (rc != EOK)
245 return rc;
[b5cf742a]246
[0bbef9b]247 if (type == SOCK_STREAM) {
[69e0d6d]248 rc = sockets_connect(verbose, socket_ids, nsockets, address,
249 addrlen);
[0bbef9b]250 if (rc != EOK)
251 return rc;
252 }
[b5cf742a]253
[69e0d6d]254 rc = sockets_sendto_recvfrom(verbose, socket_ids, nsockets, address,
255 &addrlen, data, size, nmessages);
[0bbef9b]256 if (rc != EOK)
257 return rc;
[b5cf742a]258
[0bbef9b]259 rc = sockets_close(verbose, socket_ids, nsockets);
260 if (rc != EOK)
261 return rc;
[b5cf742a]262
[0bbef9b]263 if (verbose)
264 printf("\tOK\n");
[b5cf742a]265
[0bbef9b]266 /****/
[b5cf742a]267
[0bbef9b]268 rc = sockets_create(verbose, socket_ids, nsockets, family, type);
269 if (rc != EOK)
270 return rc;
[b5cf742a]271
[0bbef9b]272 if (type == SOCK_STREAM) {
[69e0d6d]273 rc = sockets_connect(verbose, socket_ids, nsockets, address,
274 addrlen);
[0bbef9b]275 if (rc != EOK)
276 return rc;
277 }
[b5cf742a]278
[69e0d6d]279 rc = sockets_sendto(verbose, socket_ids, nsockets, address, addrlen,
280 data, size, nmessages);
[0bbef9b]281 if (rc != EOK)
282 return rc;
[b5cf742a]283
[69e0d6d]284 rc = sockets_recvfrom(verbose, socket_ids, nsockets, address, &addrlen,
285 data, size, nmessages);
[0bbef9b]286 if (rc != EOK)
287 return rc;
[b5cf742a]288
[0bbef9b]289 rc = sockets_close(verbose, socket_ids, nsockets);
290 if (rc != EOK)
291 return rc;
[b5cf742a]292
[0bbef9b]293 if (verbose)
294 printf("\tOK\n");
[b5cf742a]295
[0bbef9b]296 return EOK;
297}
[3d459fc]298
299int main(int argc, char *argv[])
300{
[69e0d6d]301 /*
302 * Parse the command line arguments. Stop before the last argument
303 * if it does not start with dash ('-')
304 */
[02a09ed]305 int index;
306 int rc;
307
308 for (index = 1; (index < argc - 1) || ((index == argc - 1) &&
309 (argv[index][0] == '-')); index++) {
[69e0d6d]310 /* Options should start with dash ('-') */
[3d459fc]311 if (argv[index][0] == '-') {
[69e0d6d]312 rc = nettest1_parse_opt(argc, argv, &index);
313 if (rc != EOK)
314 return rc;
[3d459fc]315 } else {
[3be62bc]316 nettest1_print_help();
[21580dd]317 return EINVAL;
318 }
319 }
[b5cf742a]320
[02a09ed]321 /* The last argument containing the host */
[3d459fc]322 if (index >= argc) {
[02a09ed]323 printf("Host name missing.\n");
[3be62bc]324 nettest1_print_help();
325 return EINVAL;
326 }
[02a09ed]327
328 char *addr_s = argv[argc - 1];
329
330 /* Interpret as address */
331 inet_addr_t addr_addr;
332 rc = inet_addr_parse(addr_s, &addr_addr);
333
334 if (rc != EOK) {
335 /* Interpret as a host name */
336 dnsr_hostinfo_t *hinfo = NULL;
337 rc = dnsr_name2host(addr_s, &hinfo);
338
339 if (rc != EOK) {
340 printf("Error resolving host '%s'.\n", addr_s);
341 return EINVAL;
342 }
343
344 addr_addr = hinfo->addr;
345 }
346
347 struct sockaddr_in addr;
348 struct sockaddr_in6 addr6;
349 uint16_t af = inet_addr_sockaddr_in(&addr_addr, &addr, &addr6);
350
351 if (af != family) {
352 printf("Address family does not match explicitly set family.\n");
353 return EINVAL;
354 }
355
[69e0d6d]356 /* Prepare the address buffer */
[02a09ed]357
358 switch (af) {
359 case AF_INET:
360 addr.sin_port = htons(port);
361 address = (struct sockaddr *) &addr;
362 addrlen = sizeof(addr);
[3d459fc]363 break;
[02a09ed]364 case AF_INET6:
365 addr6.sin6_port = htons(port);
366 address = (struct sockaddr *) &addr6;
367 addrlen = sizeof(addr6);
[3d459fc]368 break;
369 default:
370 fprintf(stderr, "Address family is not supported\n");
371 return EAFNOSUPPORT;
[21580dd]372 }
[b5cf742a]373
[69e0d6d]374 /* Check data buffer size */
[3d459fc]375 if (size <= 0) {
[7e752b2]376 fprintf(stderr, "Data buffer size too small (%zu). Using 1024 "
[69e0d6d]377 "bytes instead.\n", size);
[21580dd]378 size = 1024;
379 }
[b5cf742a]380
[69e0d6d]381 /*
382 * Prepare data buffer. Allocate size bytes plus one for the
383 * trailing null character.
384 */
[aadf01e]385 data = (char *) malloc(size + 1);
[3d459fc]386 if (!data) {
[aadf01e]387 fprintf(stderr, "Failed to allocate data buffer.\n");
[21580dd]388 return ENOMEM;
389 }
[69e0d6d]390 nettest1_fill_buffer(data, size);
[b5cf742a]391
[69e0d6d]392 /* Check socket count */
[3d459fc]393 if (sockets <= 0) {
[69e0d6d]394 fprintf(stderr, "Socket count too small (%d). Using "
395 "2 instead.\n", sockets);
[21580dd]396 sockets = 2;
397 }
[b5cf742a]398
[69e0d6d]399 /*
400 * Prepare socket buffer. Allocate count fields plus the terminating
401 * null (\0).
402 */
[02a09ed]403 int *socket_ids = (int *) malloc(sizeof(int) * (sockets + 1));
[3d459fc]404 if (!socket_ids) {
[aadf01e]405 fprintf(stderr, "Failed to allocate receive buffer.\n");
[21580dd]406 return ENOMEM;
407 }
[b5cf742a]408
[0b4a67a]409 socket_ids[sockets] = 0;
[b5cf742a]410
[3d459fc]411 if (verbose)
[aadf01e]412 printf("Starting tests\n");
[b5cf742a]413
[02a09ed]414 struct timeval time_before;
[0bbef9b]415 rc = gettimeofday(&time_before, NULL);
416 if (rc != EOK) {
417 fprintf(stderr, "Get time of day error %d\n", rc);
418 return rc;
[21580dd]419 }
[b5cf742a]420
[0bbef9b]421 nettest1_test(socket_ids, 1, 1);
422 nettest1_test(socket_ids, 1, messages);
423 nettest1_test(socket_ids, sockets, 1);
424 nettest1_test(socket_ids, sockets, messages);
[b5cf742a]425
[02a09ed]426 struct timeval time_after;
[0bbef9b]427 rc = gettimeofday(&time_after, NULL);
428 if (rc != EOK) {
429 fprintf(stderr, "Get time of day error %d\n", rc);
430 return rc;
[21580dd]431 }
[b5cf742a]432
[7e752b2]433 printf("Tested in %ld microseconds\n", tv_sub(&time_after,
[69e0d6d]434 &time_before));
[b5cf742a]435
[3d459fc]436 if (verbose)
[aadf01e]437 printf("Exiting\n");
[b5cf742a]438
[21580dd]439 return EOK;
440}
441
442/** @}
443 */
Note: See TracBrowser for help on using the repository browser.