Ignore:
File:
1 edited

Legend:

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

    rcd22764 r7e752b2  
    3232
    3333/** @file
    34  * Network echo server.
    35  *
    36  * Sockets-based server that echoes incomming messages. If stream mode
    37  * is selected, accepts incoming connections.
     34 * Network echo application.
     35 * Answers received packets.
    3836 */
    3937
    40 #include <assert.h>
     38#include <malloc.h>
    4139#include <stdio.h>
    42 #include <stdlib.h>
    4340#include <str.h>
    4441#include <task.h>
     
    5350#include "print_error.h"
    5451
    55 #define NAME "netecho"
    56 
    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;
     52/** Network echo module name. */
     53#define NAME    "Network Echo"
    6954
    7055static void echo_print_help(void)
    7156{
    7257        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"
     58                "Network Echo aplication\n" \
     59                "Usage: echo [options]\n" \
     60                "Where options are:\n" \
     61                "-b backlog | --backlog=size\n" \
     62                "\tThe size of the accepted sockets queue. Only for SOCK_STREAM. The default is 3.\n" \
     63                "\n" \
     64                "-c count | --count=count\n" \
     65                "\tThe number of received messages to handle. A negative number means infinity. The default is infinity.\n" \
     66                "\n" \
     67                "-f protocol_family | --family=protocol_family\n" \
     68                "\tThe listenning socket protocol family. Only the PF_INET and PF_INET6 are supported.\n"
     69                "\n" \
     70                "-h | --help\n" \
     71                "\tShow this application help.\n"
     72                "\n" \
     73                "-p port_number | --port=port_number\n" \
     74                "\tThe port number the application should listen at. The default is 7.\n" \
     75                "\n" \
     76                "-r reply_string | --reply=reply_string\n" \
     77                "\tThe constant reply string. The default is the original data received.\n" \
     78                "\n" \
     79                "-s receive_size | --size=receive_size\n" \
     80                "\tThe maximum receive data size the application should accept. The default is 1024 bytes.\n" \
     81                "\n" \
     82                "-t socket_type | --type=socket_type\n" \
     83                "\tThe listenning socket type. Only the SOCK_DGRAM and the SOCK_STREAM are supported.\n" \
     84                "\n" \
     85                "-v | --verbose\n" \
     86                "\tShow all output messages.\n"
    10987        );
    11088}
    11189
    112 static int netecho_parse_option(int argc, char *argv[], int *index)
     90int main(int argc, char *argv[])
    11391{
     92        size_t size = 1024;
     93        int verbose = 0;
     94        char *reply = NULL;
     95        sock_type_t type = SOCK_DGRAM;
     96        int count = -1;
     97        int family = PF_INET;
     98        uint16_t port = 7;
     99        int backlog = 3;
     100
     101        socklen_t max_length = sizeof(struct sockaddr_in6);
     102        uint8_t address_data[max_length];
     103        struct sockaddr *address = (struct sockaddr *) address_data;
     104        struct sockaddr_in *address_in = (struct sockaddr_in *) address;
     105        struct sockaddr_in6 *address_in6 = (struct sockaddr_in6 *) address;
     106        socklen_t addrlen;
     107        char address_string[INET6_ADDRSTRLEN];
     108        uint8_t *address_start;
     109        int socket_id;
     110        int listening_id;
     111        char *data;
     112        size_t length;
     113        int index;
     114        size_t reply_length;
    114115        int value;
    115116        int rc;
    116117
    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;
     118        // parse the command line arguments
     119        for (index = 1; index < argc; ++ index) {
     120                if (argv[index][0] == '-') {
     121                        switch (argv[index][1]) {
     122                        case 'b':
     123                                rc = arg_parse_int(argc, argv, &index, &backlog, 0);
     124                                if (rc != EOK)
     125                                        return rc;
     126                                break;
     127                        case 'c':
     128                                rc = arg_parse_int(argc, argv, &index, &count, 0);
     129                                if (rc != EOK)
     130                                        return rc;
     131                                break;
     132                        case 'f':
     133                                rc = arg_parse_name_int(argc, argv, &index, &family, 0, socket_parse_protocol_family);
     134                                if (rc != EOK)
     135                                        return rc;
     136                                break;
     137                        case 'h':
     138                                echo_print_help();
     139                                return EOK;
     140                                break;
     141                        case 'p':
     142                                rc = arg_parse_int(argc, argv, &index, &value, 0);
     143                                if (rc != EOK)
     144                                        return rc;
     145                                port = (uint16_t) value;
     146                                break;
     147                        case 'r':
     148                                rc = arg_parse_string(argc, argv, &index, &reply, 0);
     149                                if (rc != EOK)
     150                                        return rc;
     151                                break;
     152                        case 's':
     153                                rc = arg_parse_int(argc, argv, &index, &value, 0);
     154                                if (rc != EOK)
     155                                        return rc;
     156                                size = (value >= 0) ? (size_t) value : 0;
     157                                break;
     158                        case 't':
     159                                rc = arg_parse_name_int(argc, argv, &index, &value, 0, socket_parse_socket_type);
     160                                if (rc != EOK)
     161                                        return rc;
     162                                type = (sock_type_t) value;
     163                                break;
     164                        case 'v':
     165                                verbose = 1;
     166                                break;
     167                        // long options with the double minus sign ('-')
     168                        case '-':
     169                                if (str_lcmp(argv[index] + 2, "backlog=", 6) == 0) {
     170                                        rc = arg_parse_int(argc, argv, &index, &backlog, 8);
     171                                        if (rc != EOK)
     172                                                return rc;
     173                                } else if (str_lcmp(argv[index] + 2, "count=", 6) == 0) {
     174                                        rc = arg_parse_int(argc, argv, &index, &count, 8);
     175                                        if (rc != EOK)
     176                                                return rc;
     177                                } else if (str_lcmp(argv[index] + 2, "family=", 7) == 0) {
     178                                        rc = arg_parse_name_int(argc, argv, &index, &family, 9, socket_parse_protocol_family);
     179                                        if (rc != EOK)
     180                                                return rc;
     181                                } else if (str_lcmp(argv[index] + 2, "help", 5) == 0) {
     182                                        echo_print_help();
     183                                        return EOK;
     184                                } else if (str_lcmp(argv[index] + 2, "port=", 5) == 0) {
     185                                        rc = arg_parse_int(argc, argv, &index, &value, 7);
     186                                        if (rc != EOK)
     187                                                return rc;
     188                                        port = (uint16_t) value;
     189                                } else if (str_lcmp(argv[index] + 2, "reply=", 6) == 0) {
     190                                        rc = arg_parse_string(argc, argv, &index, &reply, 8);
     191                                        if (rc != EOK)
     192                                                return rc;
     193                                } else if (str_lcmp(argv[index] + 2, "size=", 5) == 0) {
     194                                        rc = arg_parse_int(argc, argv, &index, &value, 7);
     195                                        if (rc != EOK)
     196                                                return rc;
     197                                        size = (value >= 0) ? (size_t) value : 0;
     198                                } else if (str_lcmp(argv[index] + 2, "type=", 5) == 0) {
     199                                        rc = arg_parse_name_int(argc, argv, &index, &value, 7, 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                                }
     209                                break;
     210                        default:
     211                                echo_print_help();
     212                                return EINVAL;
     213                        }
    205214                } else {
    206215                        echo_print_help();
    207216                        return EINVAL;
    208217                }
    209                 break;
    210         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;
    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 
    238         int rc;
    239 
    240         if (type == SOCK_STREAM) {
    241                 /* Accept a socket if a stream socket is used */
    242                 addrlen = sizeof(address_buf);
    243                 socket_id = accept(listening_id, (void *) address_buf, &addrlen);
    244                 if (socket_id <= 0) {
    245                         socket_print_error(stderr, socket_id, "Socket accept: ", "\n");
    246                 } else {
    247                         if (verbose)
    248                                 printf("Socket %d accepted\n", socket_id);
    249                 }
    250 
    251                 assert((size_t) addrlen <= sizeof(address_buf));
    252         } else {
    253                 socket_id = listening_id;
    254         }
    255 
    256         /* if the datagram socket is used or the stream socked was accepted */
    257         if (socket_id > 0) {
    258 
    259                 /* Receive a message to echo */
    260                 rcv_size = recvfrom(socket_id, data, size, 0, address,
    261                     &addrlen);
    262                 if (rcv_size < 0) {
    263                         socket_print_error(stderr, rcv_size, "Socket receive: ", "\n");
    264                 } else {
    265                         length = (size_t) rcv_size;
    266                         if (verbose) {
    267                                 /* Print the header */
    268 
    269                                 /* Get the source port and prepare the address buffer */
    270                                 address_start = NULL;
    271                                 switch (address->sa_family) {
    272                                 case AF_INET:
    273                                         port = ntohs(address_in->sin_port);
    274                                         address_start = (uint8_t *) &address_in->sin_addr.s_addr;
    275                                         break;
    276                                 case AF_INET6:
    277                                         port = ntohs(address_in6->sin6_port);
    278                                         address_start = (uint8_t *) &address_in6->sin6_addr.s6_addr;
    279                                         break;
    280                                 default:
    281                                         fprintf(stderr, "Address family %u (%#x) is not supported.\n",
    282                                             address->sa_family, address->sa_family);
    283                                 }
    284 
    285                                 /* Parse source address */
    286                                 if (address_start) {
    287                                         rc = inet_ntop(address->sa_family, address_start, address_string, sizeof(address_string));
    288                                         if (rc != EOK) {
    289                                                 fprintf(stderr, "Received address error %d\n", rc);
    290                                         } else {
    291                                                 data[length] = '\0';
    292                                                 printf("Socket %d received %zu bytes from %s:%d\n%s\n",
    293                                                     socket_id, length, address_string, port, data);
    294                                         }
    295                                 }
    296                         }
    297 
    298                         /* Answer the request either with the static reply or the original data */
    299                         rc = sendto(socket_id, reply ? reply : data, reply ? reply_length : length, 0, address, addrlen);
    300                         if (rc != EOK)
    301                                 socket_print_error(stderr, rc, "Socket send: ", "\n");
    302                 }
    303 
    304                 /* Close accepted stream socket */
    305                 if (type == SOCK_STREAM) {
    306                         rc = closesocket(socket_id);
    307                         if (rc != EOK)
    308                                 socket_print_error(stderr, rc, "Close socket: ", "\n");
    309                 }
    310 
    311         }
    312 
    313         return EOK;
    314 }
    315 
    316 
    317 int main(int argc, char *argv[])
    318 {
    319         struct sockaddr *address;;
    320         struct sockaddr_in address_in;
    321         struct sockaddr_in6 address_in6;
    322         socklen_t addrlen;
    323 
    324         int listening_id;
    325         int index;
    326         int rc;
    327 
    328         /* Parse command line arguments */
    329         for (index = 1; index < argc; ++index) {
    330                 if (argv[index][0] == '-') {
    331                         rc = netecho_parse_option(argc, argv, &index);
    332                         if (rc != EOK)
    333                                 return rc;
    334                 } else {
    335                         echo_print_help();
    336                         return EINVAL;
    337                 }
    338         }
    339 
    340         /* Check buffer size */
     218        }
     219
     220        // check the buffer size
    341221        if (size <= 0) {
    342222                fprintf(stderr, "Receive size too small (%zu). Using 1024 bytes instead.\n", size);
    343223                size = 1024;
    344224        }
    345 
    346         /* size plus the terminating null character. */
     225        // size plus the terminating null (\0)
    347226        data = (char *) malloc(size + 1);
    348227        if (!data) {
     
    351230        }
    352231
    353         /* Set the reply size if set */
     232        // set the reply size if set
    354233        reply_length = reply ? str_length(reply) : 0;
    355234
    356         /* Prepare the address buffer */
     235        // prepare the address buffer
     236        bzero(address_data, max_length);
    357237        switch (family) {
    358238        case PF_INET:
    359                 address_in.sin_family = AF_INET;
    360                 address_in.sin_port = htons(port);
    361                 address = (struct sockaddr *) &address_in;
    362                 addrlen = sizeof(address_in);
     239                address_in->sin_family = AF_INET;
     240                address_in->sin_port = htons(port);
     241                addrlen = sizeof(struct sockaddr_in);
    363242                break;
    364243        case PF_INET6:
    365                 address_in6.sin6_family = AF_INET6;
    366                 address_in6.sin6_port = htons(port);
    367                 address = (struct sockaddr *) &address_in6;
    368                 addrlen = sizeof(address_in6);
     244                address_in6->sin6_family = AF_INET6;
     245                address_in6->sin6_port = htons(port);
     246                addrlen = sizeof(struct sockaddr_in6);
    369247                break;
    370248        default:
     
    373251        }
    374252
    375         /* Get a listening socket */
     253        // get a listening socket
    376254        listening_id = socket(family, type, 0);
    377255        if (listening_id < 0) {
     
    380258        }
    381259
    382         /* if the stream socket is used */
     260        // if the stream socket is used
    383261        if (type == SOCK_STREAM) {
    384                 /* Check backlog size */
     262                // check the backlog
    385263                if (backlog <= 0) {
    386264                        fprintf(stderr, "Accepted sockets queue size too small (%zu). Using 3 instead.\n", size);
    387265                        backlog = 3;
    388266                }
    389 
    390                 /* Set the backlog */
     267                // set the backlog
    391268                rc = listen(listening_id, backlog);
    392269                if (rc != EOK) {
     
    396273        }
    397274
    398         /* Bind the listening socket */
     275        // bind the listenning socket
    399276        rc = bind(listening_id, address, addrlen);
    400277        if (rc != EOK) {
     
    406283                printf("Socket %d listenning at %d\n", listening_id, port);
    407284
    408         /*
    409          * do count times
    410          * or indefinitely if set to a negative value
    411          */
     285        socket_id = listening_id;
     286
     287        // do count times
     288        // or indefinitely if set to a negative value
    412289        while (count) {
    413                 rc = netecho_socket_process_message(listening_id);
    414                 if (rc != EOK)
    415                         break;
    416 
    417                 /* Decrease count if positive */
     290
     291                addrlen = max_length;
     292                if (type == SOCK_STREAM) {
     293                        // acceept a socket if the stream socket is used
     294                        socket_id = accept(listening_id, address, &addrlen);
     295                        if (socket_id <= 0) {
     296                                socket_print_error(stderr, socket_id, "Socket accept: ", "\n");
     297                        } else {
     298                                if (verbose)
     299                                        printf("Socket %d accepted\n", socket_id);
     300                        }
     301                }
     302
     303                // if the datagram socket is used or the stream socked was accepted
     304                if (socket_id > 0) {
     305
     306                        // receive an echo request
     307                        value = recvfrom(socket_id, data, size, 0, address, &addrlen);
     308                        if (value < 0) {
     309                                socket_print_error(stderr, value, "Socket receive: ", "\n");
     310                        } else {
     311                                length = (size_t) value;
     312                                if (verbose) {
     313                                        // print the header
     314
     315                                        // get the source port and prepare the address buffer
     316                                        address_start = NULL;
     317                                        switch (address->sa_family) {
     318                                        case AF_INET:
     319                                                port = ntohs(address_in->sin_port);
     320                                                address_start = (uint8_t *) &address_in->sin_addr.s_addr;
     321                                                break;
     322                                        case AF_INET6:
     323                                                port = ntohs(address_in6->sin6_port);
     324                                                address_start = (uint8_t *) &address_in6->sin6_addr.s6_addr;
     325                                                break;
     326                                        default:
     327                                                fprintf(stderr, "Address family %u (%#x) is not supported.\n",
     328                                                    address->sa_family, address->sa_family);
     329                                        }
     330                                        // parse the source address
     331                                        if (address_start) {
     332                                                rc = inet_ntop(address->sa_family, address_start, address_string, sizeof(address_string));
     333                                                if (rc != EOK) {
     334                                                        fprintf(stderr, "Received address error %d\n", rc);
     335                                                } else {
     336                                                        data[length] = '\0';
     337                                                        printf("Socket %d received %zu bytes from %s:%d\n%s\n",
     338                                                            socket_id, length, address_string, port, data);
     339                                                }
     340                                        }
     341                                }
     342
     343                                // answer the request either with the static reply or the original data
     344                                rc = sendto(socket_id, reply ? reply : data, reply ? reply_length : length, 0, address, addrlen);
     345                                if (rc != EOK)
     346                                        socket_print_error(stderr, rc, "Socket send: ", "\n");
     347                        }
     348
     349                        // close the accepted stream socket
     350                        if (type == SOCK_STREAM) {
     351                                rc = closesocket(socket_id);
     352                                if (rc != EOK)
     353                                        socket_print_error(stderr, rc, "Close socket: ", "\n");
     354                        }
     355
     356                }
     357
     358                // decrease the count if positive
    418359                if (count > 0) {
    419360                        count--;
    420361                        if (verbose)
    421                                 printf("Waiting for next %d message(s)\n", count);
     362                                printf("Waiting for next %d packet(s)\n", count);
    422363                }
    423364        }
     
    426367                printf("Closing the socket\n");
    427368
    428         /* Close listenning socket */
     369        // close the listenning socket
    429370        rc = closesocket(listening_id);
    430371        if (rc != EOK) {
Note: See TracChangeset for help on using the changeset viewer.