Changes in uspace/app/netecho/netecho.c [c442f63:a62ceaf] in mainline
- File:
-
- 1 edited
Legend:
- Unmodified
- Added
- Removed
-
uspace/app/netecho/netecho.c
rc442f63 ra62ceaf 1 1 /* 2 * Copyright (c) 20 09 Lukas Mejdrech2 * Copyright (c) 2016 Jiri Svoboda 3 3 * All rights reserved. 4 4 * … … 30 30 * @{ 31 31 */ 32 33 /** @file 34 * Network echo server. 35 * 36 * Sockets-based server that echoes incomming messages. If stream mode 37 * is selected, accepts incoming connections. 38 */ 39 40 #include <assert.h> 32 /** @file Network UDP echo diagnostic utility. 33 */ 34 35 #include <stdbool.h> 36 #include <errno.h> 37 #include <io/console.h> 41 38 #include <stdio.h> 42 #include <stdlib.h>43 39 #include <str.h> 44 #include <task.h> 45 #include <arg_parse.h> 46 47 #include <net/in.h> 48 #include <net/in6.h> 49 #include <net/inet.h> 50 #include <net/socket.h> 51 #include <net/socket_parse.h> 52 53 #include "print_error.h" 40 41 #include "comm.h" 42 #include "netecho.h" 54 43 55 44 #define NAME "netecho" 56 45 57 static int count = -1; 58 static int family = PF_INET; 59 static sock_type_t type = SOCK_DGRAM; 60 static uint16_t port = 7; 61 static int backlog = 3; 62 static size_t size = 1024; 63 static int verbose = 0; 64 65 static char *reply = NULL; 66 static size_t reply_length; 67 68 static char *data; 69 70 static void echo_print_help(void) 71 { 72 printf( 73 "Network echo server\n" 74 "Usage: " NAME " [options]\n" 75 "Where options are:\n" 76 "-b backlog | --backlog=size\n" 77 "\tThe size of the accepted sockets queue. Only for SOCK_STREAM. " 78 "The default is 3.\n" 79 "\n" 80 "-c count | --count=count\n" 81 "\tThe number of received messages to handle. A negative number " 82 "means infinity. The default is infinity.\n" 83 "\n" 84 "-f protocol_family | --family=protocol_family\n" 85 "\tThe listenning socket protocol family. Only the PF_INET and " 86 "PF_INET6 are supported.\n" 87 "\n" 88 "-h | --help\n" 89 "\tShow this application help.\n" 90 "\n" 91 "-p port_number | --port=port_number\n" 92 "\tThe port number the application should listen at. The default " 93 "is 7.\n" 94 "\n" 95 "-r reply_string | --reply=reply_string\n" 96 "\tThe constant reply string. The default is the original data " 97 "received.\n" 98 "\n" 99 "-s receive_size | --size=receive_size\n" 100 "\tThe maximum receive data size the application should accept. " 101 "The default is 1024 bytes.\n" 102 "\n" 103 "-t socket_type | --type=socket_type\n" 104 "\tThe listenning socket type. Only the SOCK_DGRAM and the " 105 "SOCK_STREAM are supported.\n" 106 "\n" 107 "-v | --verbose\n" 108 "\tShow all output messages.\n" 109 ); 110 } 111 112 static int netecho_parse_option(int argc, char *argv[], int *index) 113 { 114 int value; 115 int rc; 116 117 switch (argv[*index][1]) { 118 case 'b': 119 rc = arg_parse_int(argc, argv, index, &backlog, 0); 120 if (rc != EOK) 121 return rc; 122 break; 123 case 'c': 124 rc = arg_parse_int(argc, argv, index, &count, 0); 125 if (rc != EOK) 126 return rc; 127 break; 128 case 'f': 129 rc = arg_parse_name_int(argc, argv, index, &family, 0, 130 socket_parse_protocol_family); 131 if (rc != EOK) 132 return rc; 133 break; 134 case 'h': 135 echo_print_help(); 136 exit(0); 137 break; 138 case 'p': 139 rc = arg_parse_int(argc, argv, index, &value, 0); 140 if (rc != EOK) 141 return rc; 142 port = (uint16_t) value; 143 break; 144 case 'r': 145 rc = arg_parse_string(argc, argv, index, &reply, 0); 146 if (rc != EOK) 147 return rc; 148 break; 149 case 's': 150 rc = arg_parse_int(argc, argv, index, &value, 0); 151 if (rc != EOK) 152 return rc; 153 size = (value >= 0) ? (size_t) value : 0; 154 break; 155 case 't': 156 rc = arg_parse_name_int(argc, argv, index, &value, 0, 157 socket_parse_socket_type); 158 if (rc != EOK) 159 return rc; 160 type = (sock_type_t) value; 161 break; 162 case 'v': 163 verbose = 1; 164 break; 165 /* Long options with double dash */ 166 case '-': 167 if (str_lcmp(argv[*index] + 2, "backlog=", 6) == 0) { 168 rc = arg_parse_int(argc, argv, index, &backlog, 8); 169 if (rc != EOK) 170 return rc; 171 } else if (str_lcmp(argv[*index] + 2, "count=", 6) == 0) { 172 rc = arg_parse_int(argc, argv, index, &count, 8); 173 if (rc != EOK) 174 return rc; 175 } else if (str_lcmp(argv[*index] + 2, "family=", 7) == 0) { 176 rc = arg_parse_name_int(argc, argv, index, &family, 9, 177 socket_parse_protocol_family); 178 if (rc != EOK) 179 return rc; 180 } else if (str_lcmp(argv[*index] + 2, "help", 5) == 0) { 181 echo_print_help(); 182 exit(0); 183 } else if (str_lcmp(argv[*index] + 2, "port=", 5) == 0) { 184 rc = arg_parse_int(argc, argv, index, &value, 7); 185 if (rc != EOK) 186 return rc; 187 port = (uint16_t) value; 188 } else if (str_lcmp(argv[*index] + 2, "reply=", 6) == 0) { 189 rc = arg_parse_string(argc, argv, index, &reply, 8); 190 if (rc != EOK) 191 return rc; 192 } else if (str_lcmp(argv[*index] + 2, "size=", 5) == 0) { 193 rc = arg_parse_int(argc, argv, index, &value, 7); 194 if (rc != EOK) 195 return rc; 196 size = (value >= 0) ? (size_t) value : 0; 197 } else if (str_lcmp(argv[*index] + 2, "type=", 5) == 0) { 198 rc = arg_parse_name_int(argc, argv, index, &value, 7, 199 socket_parse_socket_type); 200 if (rc != EOK) 201 return rc; 202 type = (sock_type_t) value; 203 } else if (str_lcmp(argv[*index] + 2, "verbose", 8) == 0) { 204 verbose = 1; 205 } else { 206 echo_print_help(); 207 return EINVAL; 208 } 46 static console_ctrl_t *con; 47 static bool done; 48 49 void netecho_received(void *data, size_t size) 50 { 51 char *p; 52 size_t i; 53 54 printf("Received message '"); 55 p = data; 56 57 for (i = 0; i < size; i++) 58 putchar(p[i]); 59 printf("'.\n"); 60 } 61 62 static void key_handle_ctrl(kbd_event_t *ev) 63 { 64 switch (ev->key) { 65 case KC_Q: 66 done = true; 209 67 break; 210 68 default: 211 echo_print_help(); 212 return EINVAL; 213 } 214 215 return EOK; 216 } 217 218 /** Echo one message (accept one connection and echo message). 219 * 220 * @param listening_id Listening socket. 221 * @return EOK on success or negative error code. 222 */ 223 static int netecho_socket_process_message(int listening_id) 224 { 225 uint8_t address_buf[sizeof(struct sockaddr_in6)]; 226 227 socklen_t addrlen = sizeof(struct sockaddr_in6); 228 int socket_id; 229 ssize_t rcv_size; 230 size_t length; 231 uint8_t *address_start; 232 233 char address_string[INET6_ADDRSTRLEN]; 234 struct sockaddr_in *address_in = (struct sockaddr_in *) address_buf; 235 struct sockaddr_in6 *address_in6 = (struct sockaddr_in6 *) address_buf; 236 struct sockaddr *address = (struct sockaddr *) address_buf; 237 69 break; 70 } 71 } 72 73 static void send_char(wchar_t c) 74 { 75 char cbuf[STR_BOUNDS(1)]; 76 size_t offs; 238 77 int rc; 239 78 240 if (type == SOCK_STREAM) { 241 /* Accept a socket if a stream socket is used */ 242 if (verbose) 243 printf("accept()\n"); 244 socket_id = accept(listening_id, (void *) address_buf, &addrlen); 245 if (socket_id <= 0) { 246 socket_print_error(stderr, socket_id, "Socket accept: ", "\n"); 247 } else { 248 if (verbose) 249 printf("Socket %d accepted\n", socket_id); 250 } 251 252 assert((size_t) addrlen <= sizeof(address_buf)); 253 } else { 254 socket_id = listening_id; 255 } 256 257 /* if the datagram socket is used or the stream socked was accepted */ 258 if (socket_id > 0) { 259 260 /* Receive a message to echo */ 261 if (verbose) 262 printf("recvfrom()\n"); 263 rcv_size = recvfrom(socket_id, data, size, 0, address, 264 &addrlen); 265 if (rcv_size < 0) { 266 socket_print_error(stderr, rcv_size, "Socket receive: ", "\n"); 267 } else { 268 length = (size_t) rcv_size; 269 if (verbose) { 270 /* Print the header */ 271 272 /* Get the source port and prepare the address buffer */ 273 address_start = NULL; 274 switch (address->sa_family) { 275 case AF_INET: 276 port = ntohs(address_in->sin_port); 277 address_start = (uint8_t *) &address_in->sin_addr.s_addr; 278 break; 279 case AF_INET6: 280 port = ntohs(address_in6->sin6_port); 281 address_start = (uint8_t *) address_in6->sin6_addr.s6_addr; 282 break; 283 default: 284 fprintf(stderr, "Address family %u (%#x) is not supported.\n", 285 address->sa_family, address->sa_family); 286 } 287 288 /* Parse source address */ 289 if (address_start) { 290 rc = inet_ntop(address->sa_family, address_start, address_string, sizeof(address_string)); 291 if (rc != EOK) { 292 fprintf(stderr, "Received address error %d\n", rc); 293 } else { 294 data[length] = '\0'; 295 printf("Socket %d received %zu bytes from %s:%d\n%s\n", 296 socket_id, length, address_string, port, data); 297 } 298 } 299 } 300 301 /* Answer the request either with the static reply or the original data */ 302 if (type == SOCK_STREAM) { 303 if (verbose) 304 printf("send()\n"); 305 rc = send(socket_id, reply ? reply : data, reply ? reply_length : length, 0); 306 if (rc != EOK) 307 socket_print_error(stderr, rc, "Socket send: ", "\n"); 308 } else { 309 if (verbose) 310 printf("sendto()\n"); 311 rc = sendto(socket_id, reply ? reply : data, reply ? reply_length : length, 0, address, addrlen); 312 if (rc != EOK) 313 socket_print_error(stderr, rc, "Socket sendto: ", "\n"); 314 } 315 } 316 317 /* Close accepted stream socket */ 318 if (type == SOCK_STREAM) { 319 rc = closesocket(socket_id); 320 if (rc != EOK) 321 socket_print_error(stderr, rc, "Close socket: ", "\n"); 322 } 323 324 } 325 326 return EOK; 327 } 328 329 330 int main(int argc, char *argv[]) 331 { 332 struct sockaddr *address;; 333 struct sockaddr_in address_in; 334 struct sockaddr_in6 address_in6; 335 socklen_t addrlen; 336 337 int listening_id; 338 int index; 339 int rc; 340 341 /* Parse command line arguments */ 342 for (index = 1; index < argc; ++index) { 343 if (argv[index][0] == '-') { 344 rc = netecho_parse_option(argc, argv, &index); 345 if (rc != EOK) 346 return rc; 347 } else { 348 echo_print_help(); 349 return EINVAL; 350 } 351 } 352 353 /* Check buffer size */ 354 if (size <= 0) { 355 fprintf(stderr, "Receive size too small (%zu). Using 1024 bytes instead.\n", size); 356 size = 1024; 357 } 358 359 /* size plus the terminating null character. */ 360 data = (char *) malloc(size + 1); 361 if (!data) { 362 fprintf(stderr, "Failed to allocate receive buffer.\n"); 363 return ENOMEM; 364 } 365 366 /* Set the reply size if set */ 367 reply_length = reply ? str_length(reply) : 0; 368 369 /* Prepare the address buffer */ 370 switch (family) { 371 case PF_INET: 372 address_in.sin_family = AF_INET; 373 address_in.sin_port = htons(port); 374 address_in.sin_addr.s_addr = INADDR_ANY; 375 address = (struct sockaddr *) &address_in; 376 addrlen = sizeof(address_in); 377 break; 378 case PF_INET6: 379 address_in6.sin6_family = AF_INET6; 380 address_in6.sin6_port = htons(port); 381 address_in6.sin6_addr = in6addr_any; 382 address = (struct sockaddr *) &address_in6; 383 addrlen = sizeof(address_in6); 79 offs = 0; 80 chr_encode(c, cbuf, &offs, STR_BOUNDS(1)); 81 82 rc = comm_send(cbuf, offs); 83 if (rc != EOK) { 84 printf("[Failed sending data]\n"); 85 } 86 } 87 88 static void key_handle_unmod(kbd_event_t *ev) 89 { 90 switch (ev->key) { 91 case KC_ENTER: 92 send_char('\n'); 384 93 break; 385 94 default: 386 fprintf(stderr, "Protocol family is not supported\n"); 387 return EAFNOSUPPORT; 388 } 389 390 /* Get a listening socket */ 391 listening_id = socket(family, type, 0); 392 if (listening_id < 0) { 393 socket_print_error(stderr, listening_id, "Socket create: ", "\n"); 394 return listening_id; 395 } 396 397 /* Bind the listening socket */ 398 rc = bind(listening_id, address, addrlen); 399 if (rc != EOK) { 400 socket_print_error(stderr, rc, "Socket bind: ", "\n"); 401 return rc; 402 } 403 404 /* if the stream socket is used */ 405 if (type == SOCK_STREAM) { 406 /* Check backlog size */ 407 if (backlog <= 0) { 408 fprintf(stderr, "Accepted sockets queue size too small (%zu). Using 3 instead.\n", size); 409 backlog = 3; 410 } 411 412 /* Set the backlog */ 413 rc = listen(listening_id, backlog); 95 if (ev->c >= 32 || ev->c == '\t' || ev->c == '\b') { 96 send_char(ev->c); 97 } 98 } 99 } 100 101 static void key_handle(kbd_event_t *ev) 102 { 103 if ((ev->mods & KM_ALT) == 0 && 104 (ev->mods & KM_SHIFT) == 0 && 105 (ev->mods & KM_CTRL) != 0) { 106 key_handle_ctrl(ev); 107 } else if ((ev->mods & (KM_CTRL | KM_ALT)) == 0) { 108 key_handle_unmod(ev); 109 } 110 } 111 112 113 static void print_syntax(void) 114 { 115 printf("syntax:\n"); 116 printf("\t%s -l <port>\n", NAME); 117 printf("\t%s -d <host>:<port> [<message> [<message...>]]\n", NAME); 118 } 119 120 /* Interactive mode */ 121 static void netecho_interact(void) 122 { 123 cons_event_t ev; 124 125 printf("Communication started. Press Ctrl-Q to quit.\n"); 126 127 con = console_init(stdin, stdout); 128 129 done = false; 130 while (!done) { 131 console_get_event(con, &ev); 132 if (ev.type == CEV_KEY && ev.ev.key.type == KEY_PRESS) 133 key_handle(&ev.ev.key); 134 } 135 } 136 137 static void netecho_send_messages(char **msgs) 138 { 139 int rc; 140 141 while (*msgs != NULL) { 142 rc = comm_send(*msgs, str_size(*msgs)); 414 143 if (rc != EOK) { 415 socket_print_error(stderr, rc, "Socket listen: ", "\n"); 416 return rc; 417 } 418 } 419 420 if (verbose) 421 printf("Socket %d listenning at %d\n", listening_id, port); 422 423 /* 424 * do count times 425 * or indefinitely if set to a negative value 426 */ 427 while (count) { 428 rc = netecho_socket_process_message(listening_id); 429 if (rc != EOK) 430 break; 431 432 /* Decrease count if positive */ 433 if (count > 0) { 434 count--; 435 if (verbose) 436 printf("Waiting for next %d message(s)\n", count); 437 } 438 } 439 440 if (verbose) 441 printf("Closing the socket\n"); 442 443 /* Close listenning socket */ 444 rc = closesocket(listening_id); 445 if (rc != EOK) { 446 socket_print_error(stderr, rc, "Close socket: ", "\n"); 447 return rc; 448 } 449 450 if (verbose) 451 printf("Exiting\n"); 452 453 return EOK; 144 printf("[Failed sending data]\n"); 145 } 146 147 ++msgs; 148 } 149 } 150 151 int main(int argc, char *argv[]) 152 { 153 char *hostport; 154 char *port; 155 char **msgs; 156 int rc; 157 158 if (argc < 2) { 159 print_syntax(); 160 return 1; 161 } 162 163 if (str_cmp(argv[1], "-l") == 0) { 164 if (argc != 3) { 165 print_syntax(); 166 return 1; 167 } 168 169 port = argv[2]; 170 msgs = NULL; 171 172 rc = comm_open_listen(port); 173 if (rc != EOK) { 174 printf("Error setting up communication.\n"); 175 return 1; 176 } 177 } else if (str_cmp(argv[1], "-d") == 0) { 178 if (argc < 3) { 179 print_syntax(); 180 return 1; 181 } 182 183 hostport = argv[2]; 184 port = NULL; 185 msgs = argv + 3; 186 187 rc = comm_open_talkto(hostport); 188 if (rc != EOK) { 189 printf("Error setting up communication.\n"); 190 return 1; 191 } 192 } else { 193 print_syntax(); 194 return 1; 195 } 196 197 if (msgs != NULL && *msgs != NULL) { 198 /* Just send messages and quit */ 199 netecho_send_messages(msgs); 200 } else { 201 /* Interactive mode */ 202 netecho_interact(); 203 } 204 205 comm_close(); 206 return 0; 454 207 } 455 208
Note:
See TracChangeset
for help on using the changeset viewer.