Ignore:
File:
1 edited

Legend:

Unmodified
Added
Removed
  • uspace/app/netecho/netecho.c

    rc442f63 ra62ceaf  
    11/*
    2  * Copyright (c) 2009 Lukas Mejdrech
     2 * Copyright (c) 2016 Jiri Svoboda
    33 * All rights reserved.
    44 *
     
    3030 * @{
    3131 */
    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>
    4138#include <stdio.h>
    42 #include <stdlib.h>
    4339#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"
    5443
    5544#define NAME "netecho"
    5645
    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                 }
     46static console_ctrl_t *con;
     47static bool done;
     48
     49void 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
     62static void key_handle_ctrl(kbd_event_t *ev)
     63{
     64        switch (ev->key) {
     65        case KC_Q:
     66                done = true;
    20967                break;
    21068        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
     73static void send_char(wchar_t c)
     74{
     75        char cbuf[STR_BOUNDS(1)];
     76        size_t offs;
    23877        int rc;
    23978
    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
     88static void key_handle_unmod(kbd_event_t *ev)
     89{
     90        switch (ev->key) {
     91        case KC_ENTER:
     92                send_char('\n');
    38493                break;
    38594        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
     101static 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
     113static 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 */
     121static 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
     137static void netecho_send_messages(char **msgs)
     138{
     139        int rc;
     140
     141        while (*msgs != NULL) {
     142                rc = comm_send(*msgs, str_size(*msgs));
    414143                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
     151int 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;
    454207}
    455208
Note: See TracChangeset for help on using the changeset viewer.