source: mainline/uspace/app/netspeed/netspeed.c@ 67fbd5e

lfn serial ticket/834-toolchain-update topic/msim-upgrade topic/simplify-dev-export
Last change on this file since 67fbd5e was fada53f, checked in by Martin Sucha <sucha14@…>, 12 years ago

Add basic netspeed utility.

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