source: mainline/uspace/app/nettest1/nettest1.c@ 19a4f73

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

new network address infrastructure (towards IPv6 support)

  • Property mode set to 100644
File size: 10.8 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. */
[21580dd]56#define NAME "Nettest1"
57
[3d459fc]58/** Packet data pattern. */
[21580dd]59#define NETTEST1_TEXT "Networking test 1 - sockets"
60
[69e0d6d]61static int family = PF_INET;
62static sock_type_t type = SOCK_DGRAM;
63static char *data;
64static size_t size = 27;
65static int verbose = 0;
[0bbef9b]66
[69e0d6d]67static struct sockaddr *address;
68static socklen_t addrlen;
69
70static int sockets;
71static int messages;
72static uint16_t port;
[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;
116
117 switch (argv[*index][1]) {
118 /*
119 * Short options with only one letter
120 */
121 case 'f':
122 rc = arg_parse_name_int(argc, argv, index, &family, 0, socket_parse_protocol_family);
123 if (rc != EOK)
124 return rc;
125 break;
126 case 'h':
127 nettest1_print_help();
128 return EOK;
129 case 'm':
130 rc = arg_parse_int(argc, argv, index, &messages, 0);
131 if (rc != EOK)
132 return rc;
133 break;
134 case 'n':
135 rc = arg_parse_int(argc, argv, index, &sockets, 0);
136 if (rc != EOK)
137 return rc;
138 break;
139 case 'p':
140 rc = arg_parse_int(argc, argv, index, &value, 0);
141 if (rc != EOK)
142 return rc;
143 port = (uint16_t) value;
144 break;
145 case 's':
146 rc = arg_parse_int(argc, argv, index, &value, 0);
147 if (rc != EOK)
148 return rc;
149 size = (value >= 0) ? (size_t) value : 0;
150 break;
151 case 't':
152 rc = arg_parse_name_int(argc, argv, index, &value, 0, socket_parse_socket_type);
153 if (rc != EOK)
154 return rc;
155 type = (sock_type_t) value;
156 break;
157 case 'v':
158 verbose = 1;
159 break;
160 /*
161 * Long options with double dash ('-')
162 */
163 case '-':
164 if (str_lcmp(argv[*index] + 2, "family=", 7) == 0) {
165 rc = arg_parse_name_int(argc, argv, index, &family, 9,
166 socket_parse_protocol_family);
167 if (rc != EOK)
168 return rc;
169 } else if (str_lcmp(argv[*index] + 2, "help", 5) == 0) {
170 nettest1_print_help();
171 return EOK;
172 } else if (str_lcmp(argv[*index] + 2, "messages=", 6) == 0) {
173 rc = arg_parse_int(argc, argv, index, &messages, 8);
174 if (rc != EOK)
175 return rc;
176 } else if (str_lcmp(argv[*index] + 2, "sockets=", 6) == 0) {
177 rc = arg_parse_int(argc, argv, index, &sockets, 8);
178 if (rc != EOK)
179 return rc;
180 } else if (str_lcmp(argv[*index] + 2, "port=", 5) == 0) {
181 rc = arg_parse_int(argc, argv, index, &value, 7);
182 if (rc != EOK)
183 return rc;
184 port = (uint16_t) value;
185 } else if (str_lcmp(argv[*index] + 2, "type=", 5) == 0) {
186 rc = arg_parse_name_int(argc, argv, index, &value, 7,
187 socket_parse_socket_type);
188 if (rc != EOK)
189 return rc;
190 type = (sock_type_t) value;
191 } else if (str_lcmp(argv[*index] + 2, "verbose", 8) == 0) {
192 verbose = 1;
193 } else {
194 nettest1_print_help();
195 return EINVAL;
196 }
197 break;
198 default:
199 nettest1_print_help();
200 return EINVAL;
201 }
202
203 return EOK;
204}
205
206/** Fill buffer with the NETTEST1_TEXT pattern.
[3d459fc]207 *
[69e0d6d]208 * @param buffer Data buffer.
209 * @param size Buffer size in bytes.
[21580dd]210 */
[69e0d6d]211static void nettest1_fill_buffer(char *buffer, size_t size)
[3d459fc]212{
213 size_t length;
214
215 length = 0;
216 while (size > length + sizeof(NETTEST1_TEXT) - 1) {
[69e0d6d]217 memcpy(buffer + length, NETTEST1_TEXT,
218 sizeof(NETTEST1_TEXT) - 1);
[3d459fc]219 length += sizeof(NETTEST1_TEXT) - 1;
220 }
[69e0d6d]221
222 memcpy(buffer + length, NETTEST1_TEXT, size - length);
223 buffer[size] = '\0';
[3d459fc]224}
[21580dd]225
[0bbef9b]226static int nettest1_test(int *socket_ids, int nsockets, int nmessages)
227{
228 int rc;
229
230 if (verbose)
231 printf("%d sockets, %d messages\n", nsockets, nmessages);
232
233 rc = sockets_create(verbose, socket_ids, nsockets, family, type);
234 if (rc != EOK)
235 return rc;
236
237 if (type == SOCK_STREAM) {
[69e0d6d]238 rc = sockets_connect(verbose, socket_ids, nsockets, address,
239 addrlen);
[0bbef9b]240 if (rc != EOK)
241 return rc;
242 }
243
[69e0d6d]244 rc = sockets_sendto_recvfrom(verbose, socket_ids, nsockets, address,
245 &addrlen, data, size, nmessages);
[0bbef9b]246 if (rc != EOK)
247 return rc;
248
249 rc = sockets_close(verbose, socket_ids, nsockets);
250 if (rc != EOK)
251 return rc;
252
253 if (verbose)
254 printf("\tOK\n");
255
256 /****/
257
258 rc = sockets_create(verbose, socket_ids, nsockets, family, type);
259 if (rc != EOK)
260 return rc;
261
262 if (type == SOCK_STREAM) {
[69e0d6d]263 rc = sockets_connect(verbose, socket_ids, nsockets, address,
264 addrlen);
[0bbef9b]265 if (rc != EOK)
266 return rc;
267 }
268
[69e0d6d]269 rc = sockets_sendto(verbose, socket_ids, nsockets, address, addrlen,
270 data, size, nmessages);
[0bbef9b]271 if (rc != EOK)
272 return rc;
273
[69e0d6d]274 rc = sockets_recvfrom(verbose, socket_ids, nsockets, address, &addrlen,
275 data, size, nmessages);
[0bbef9b]276 if (rc != EOK)
277 return rc;
278
279 rc = sockets_close(verbose, socket_ids, nsockets);
280 if (rc != EOK)
281 return rc;
282
283 if (verbose)
284 printf("\tOK\n");
285
286 return EOK;
287}
[3d459fc]288
289int main(int argc, char *argv[])
290{
[c9ebbe71]291 struct sockaddr_in address_in;
292 struct sockaddr_in6 address_in6;
[287d729]293 dnsr_hostinfo_t *hinfo;
[3d459fc]294 uint8_t *address_start;
[aadf01e]295
[3d459fc]296 int *socket_ids;
[aadf01e]297 int index;
298 struct timeval time_before;
299 struct timeval time_after;
[21580dd]300
[0bbef9b]301 int rc;
302
[69e0d6d]303 sockets = 10;
304 messages = 10;
305 port = 7;
306
307 /*
308 * Parse the command line arguments. Stop before the last argument
309 * if it does not start with dash ('-')
310 */
[3d459fc]311 for (index = 1; (index < argc - 1) || ((index == argc - 1) && (argv[index][0] == '-')); index++) {
[69e0d6d]312 /* Options should start with dash ('-') */
[3d459fc]313 if (argv[index][0] == '-') {
[69e0d6d]314 rc = nettest1_parse_opt(argc, argv, &index);
315 if (rc != EOK)
316 return rc;
[3d459fc]317 } else {
[3be62bc]318 nettest1_print_help();
[21580dd]319 return EINVAL;
320 }
321 }
322
[287d729]323 /* If not before the last argument containing the host */
[3d459fc]324 if (index >= argc) {
[287d729]325 printf("Command line error: missing host name\n");
[3be62bc]326 nettest1_print_help();
327 return EINVAL;
328 }
329
[69e0d6d]330 /* Prepare the address buffer */
331
[3d459fc]332 switch (family) {
333 case PF_INET:
[c9ebbe71]334 address_in.sin_family = AF_INET;
335 address_in.sin_port = htons(port);
336 address = (struct sockaddr *) &address_in;
337 addrlen = sizeof(address_in);
338 address_start = (uint8_t *) &address_in.sin_addr.s_addr;
[3d459fc]339 break;
340 case PF_INET6:
[c9ebbe71]341 address_in6.sin6_family = AF_INET6;
342 address_in6.sin6_port = htons(port);
343 address = (struct sockaddr *) &address_in6;
344 addrlen = sizeof(address_in6);
345 address_start = (uint8_t *) &address_in6.sin6_addr.s6_addr;
[3d459fc]346 break;
347 default:
348 fprintf(stderr, "Address family is not supported\n");
349 return EAFNOSUPPORT;
[21580dd]350 }
351
[287d729]352 /* Parse the last argument which should contain the host/address */
[0bbef9b]353 rc = inet_pton(family, argv[argc - 1], address_start);
354 if (rc != EOK) {
[287d729]355 /* Try interpreting as a host name */
356 rc = dnsr_name2host(argv[argc - 1], &hinfo);
357 if (rc != EOK) {
358 printf("Error resolving host '%s'.\n", argv[argc - 1]);
359 return rc;
360 }
[3e66428]361
362 rc = inet2_addr_sockaddr_in(&hinfo->addr, &address_in);
363 if (rc != EOK) {
364 printf("Host '%s' not resolved as IPv4 address.\n", argv[argc - 1]);
365 return rc;
366 }
[21580dd]367 }
368
[69e0d6d]369 /* Check data buffer size */
[3d459fc]370 if (size <= 0) {
[7e752b2]371 fprintf(stderr, "Data buffer size too small (%zu). Using 1024 "
[69e0d6d]372 "bytes instead.\n", size);
[21580dd]373 size = 1024;
374 }
[3be62bc]375
[69e0d6d]376 /*
377 * Prepare data buffer. Allocate size bytes plus one for the
378 * trailing null character.
379 */
[aadf01e]380 data = (char *) malloc(size + 1);
[3d459fc]381 if (!data) {
[aadf01e]382 fprintf(stderr, "Failed to allocate data buffer.\n");
[21580dd]383 return ENOMEM;
384 }
[69e0d6d]385 nettest1_fill_buffer(data, size);
[21580dd]386
[69e0d6d]387 /* Check socket count */
[3d459fc]388 if (sockets <= 0) {
[69e0d6d]389 fprintf(stderr, "Socket count too small (%d). Using "
390 "2 instead.\n", sockets);
[21580dd]391 sockets = 2;
392 }
[3be62bc]393
[69e0d6d]394 /*
395 * Prepare socket buffer. Allocate count fields plus the terminating
396 * null (\0).
397 */
[aadf01e]398 socket_ids = (int *) malloc(sizeof(int) * (sockets + 1));
[3d459fc]399 if (!socket_ids) {
[aadf01e]400 fprintf(stderr, "Failed to allocate receive buffer.\n");
[21580dd]401 return ENOMEM;
402 }
[0b4a67a]403 socket_ids[sockets] = 0;
[21580dd]404
[3d459fc]405 if (verbose)
[aadf01e]406 printf("Starting tests\n");
[21580dd]407
[0bbef9b]408 rc = gettimeofday(&time_before, NULL);
409 if (rc != EOK) {
410 fprintf(stderr, "Get time of day error %d\n", rc);
411 return rc;
[21580dd]412 }
413
[0bbef9b]414 nettest1_test(socket_ids, 1, 1);
415 nettest1_test(socket_ids, 1, messages);
416 nettest1_test(socket_ids, sockets, 1);
417 nettest1_test(socket_ids, sockets, messages);
[21580dd]418
[0bbef9b]419 rc = gettimeofday(&time_after, NULL);
420 if (rc != EOK) {
421 fprintf(stderr, "Get time of day error %d\n", rc);
422 return rc;
[21580dd]423 }
424
[7e752b2]425 printf("Tested in %ld microseconds\n", tv_sub(&time_after,
[69e0d6d]426 &time_before));
[21580dd]427
[3d459fc]428 if (verbose)
[aadf01e]429 printf("Exiting\n");
[21580dd]430
431 return EOK;
432}
433
[3be62bc]434
[21580dd]435/** @}
436 */
Note: See TracBrowser for help on using the repository browser.