source: mainline/uspace/app/netspeed/netspeed.c@ 75baf6e

lfn serial ticket/834-toolchain-update topic/msim-upgrade topic/simplify-dev-export
Last change on this file since 75baf6e was 26de91a, checked in by Jiri Svoboda <jiri@…>, 12 years ago

IPv4 and v6 should not need separate handling by a simple client that is just connecting to a host/address. Add IPv6/DNS support in applications where missing.

  • Property mode set to 100644
File size: 6.7 KB
Line 
1/*
2 * Copyright (c) 2013 Martin Sucha
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 netspeed
30 * @{
31 */
32
33/** @file
34 * Network speed measurement (iperf counterpart)
35 *
36 */
37
38#include <assert.h>
39#include <inet/dnsr.h>
40#include <net/in.h>
41#include <net/inet.h>
42#include <net/socket.h>
43#include <stdio.h>
44#include <stdlib.h>
45#include <str.h>
46#include <str_error.h>
47#include <task.h>
48
49#define NAME "netspeed"
50
51static int server(sock_type_t sock_type, unsigned port, void *buf, size_t bufsize)
52{
53 struct sockaddr_in addr;
54
55 addr.sin_family = AF_INET;
56 addr.sin_port = htons(port);
57
58 int rc = inet_pton(AF_INET, "127.0.0.1", (void *)
59 &addr.sin_addr.s_addr);
60 if (rc != EOK) {
61 fprintf(stderr, "inet_pton failed: %s\n", str_error(rc));
62 return rc;
63 }
64
65 int listen_sd = socket(PF_INET, sock_type, 0);
66 if (listen_sd < 0) {
67 fprintf(stderr, "socket failed: %s\n", str_error(rc));
68 return rc;
69 }
70
71 rc = bind(listen_sd, (struct sockaddr *) &addr, sizeof(addr));
72 if (rc != EOK) {
73 fprintf(stderr, "bind failed: %s\n", str_error(rc));
74 closesocket(listen_sd);
75 return rc;
76 }
77
78 rc = listen(listen_sd, 2);
79 if (rc != EOK) {
80 fprintf(stderr, "listen failed: %s\n", str_error(rc));
81 closesocket(listen_sd);
82 return rc;
83 }
84
85 int conn_sd;
86 struct sockaddr_in raddr;
87 socklen_t raddr_len = sizeof(raddr);
88 if (sock_type == SOCK_STREAM) {
89 conn_sd = accept(listen_sd, (struct sockaddr *) &raddr,
90 &raddr_len);
91 if (conn_sd < 0) {
92 fprintf(stderr, "accept failed: %s\n", str_error(conn_sd));
93 closesocket(listen_sd);
94 return conn_sd;
95 }
96 } else {
97 conn_sd = listen_sd;
98 }
99
100 while (true) {
101 rc = recvfrom(conn_sd, buf, bufsize, 0, (struct sockaddr *) &raddr,
102 &raddr_len);
103 if (rc <= 0) {
104 if (rc < 0)
105 fprintf(stderr, "recvfrom failed: %s\n", str_error(rc));
106 break;
107 }
108 }
109
110 if (sock_type == SOCK_STREAM)
111 closesocket(conn_sd);
112 closesocket(listen_sd);
113
114 return rc;
115}
116
117static int client(sock_type_t sock_type, const char *host, unsigned port,
118 unsigned long count, char *buf, size_t bufsize)
119{
120 inet_addr_t iaddr;
121 struct sockaddr *saddr;
122 socklen_t saddrlen;
123
124 int rc = inet_addr_parse(host, &iaddr);
125 if (rc != EOK) {
126 dnsr_hostinfo_t *hinfo = NULL;
127 rc = dnsr_name2host(host, &hinfo, ip_any);
128 if (rc != EOK) {
129 fprintf(stderr, "Error resolving host '%s'.\n", host);
130 return ENOENT;
131 }
132
133 iaddr = hinfo->addr;
134 }
135
136 rc = inet_addr_sockaddr(&iaddr, port, &saddr, &saddrlen);
137 if (rc != EOK) {
138 assert(rc == ENOMEM);
139 fprintf(stderr, "Out of memory.\n");
140 return ENOMEM;
141 }
142
143 int conn_sd = socket(saddr->sa_family, sock_type, 0);
144 if (conn_sd < 0) {
145 fprintf(stderr, "socket failed: %s\n", str_error(rc));
146 return rc;
147 }
148
149 if (sock_type == SOCK_STREAM) {
150 rc = connect(conn_sd, saddr, saddrlen);
151 if (rc != EOK) {
152 fprintf(stderr, "connect failed: %s\n", str_error(rc));
153 closesocket(conn_sd);
154 return rc;
155 }
156 }
157
158 for (size_t pos = 0; pos < bufsize; pos++) {
159 buf[pos] = '0' + (pos % 10);
160 }
161
162 for (unsigned long i = 0; i < count; i++) {
163 if (sock_type == SOCK_STREAM) {
164 rc = send(conn_sd, buf, bufsize, 0);
165 } else {
166 rc = sendto(conn_sd, buf, bufsize, 0, saddr, saddrlen);
167 }
168 if (rc != EOK) {
169 fprintf(stderr, "send failed: %s\n", str_error(rc));
170 break;
171 }
172 }
173
174 closesocket(conn_sd);
175 free(saddr);
176 return rc;
177}
178
179static void syntax_print(void)
180{
181 fprintf(stderr, "Usage: netspeed <tcp|udp> server [port] <buffer size>\n");
182 fprintf(stderr, " netspeed <tcp|udp> client <host> <port> <count> <buffer size>\n");
183}
184
185int main(int argc, char *argv[])
186{
187 if (argc < 3) {
188 syntax_print();
189 return 2;
190 }
191
192 sock_type_t sock_type;
193 if (str_cmp(argv[1], "tcp") == 0) {
194 sock_type = SOCK_STREAM;
195 } else if (str_cmp(argv[1], "udp") == 0) {
196 sock_type = SOCK_DGRAM;
197 } else {
198 fprintf(stderr, "Invalid socket type\n");
199 syntax_print();
200 return 1;
201 }
202
203 char *endptr;
204 int arg = 3;
205 unsigned long port = 5001;
206 const char *address;
207 bool is_server;
208 unsigned long count = 0;
209
210 if (str_cmp(argv[2], "server") == 0) {
211 is_server = true;
212 if (argc < 4) {
213 syntax_print();
214 return 2;
215 }
216 if (argc > 4) {
217 port = strtoul(argv[3], &endptr, 0);
218 if (*endptr != 0) {
219 fprintf(stderr, "Invalid port number\n");
220 syntax_print();
221 return 1;
222 }
223 arg = 4;
224 }
225 }
226 else if (str_cmp(argv[2], "client") == 0) {
227 is_server = false;
228 if (argc < 6) {
229 syntax_print();
230 return 2;
231 }
232 address = argv[3];
233 port = strtoul(argv[4], &endptr, 0);
234 if (*endptr != 0) {
235 fprintf(stderr, "Invalid port number\n");
236 syntax_print();
237 return 1;
238 }
239
240 count = strtoul(argv[5], &endptr, 0);
241 if (*endptr != 0) {
242 fprintf(stderr, "Invalid count\n");
243 syntax_print();
244 return 1;
245 }
246
247 arg = 6;
248 }
249 else {
250 fprintf(stderr, "Invalid client/server mode\n");
251 syntax_print();
252 return 2;
253 }
254
255 if (argc < arg + 1) {
256 syntax_print();
257 return 2;
258 }
259
260 unsigned long bufsize = strtoul(argv[arg], &endptr, 0);
261 if (*endptr != 0 || bufsize == 0) {
262 fprintf(stderr, "Invalid buffer size\n");
263 syntax_print();
264 return 1;
265 }
266
267 void *buf = malloc(bufsize);
268 if (buf == NULL) {
269 fprintf(stderr, "Cannot allocate buffer\n");
270 return ENOMEM;
271 }
272
273 int rc = EOK;
274 if (is_server) {
275 rc = server(sock_type, port, buf, bufsize);
276 if (rc != EOK)
277 fprintf(stderr, "Server failed: %s\n", str_error(rc));
278 } else {
279 rc = client(sock_type, address, port, count, buf, bufsize);
280 if (rc != EOK)
281 fprintf(stderr, "Client failed: %s\n", str_error(rc));
282 }
283
284 free(buf);
285
286 return rc;
287}
288
289/** @}
290 */
Note: See TracBrowser for help on using the repository browser.