Ignore:
File:
1 edited

Legend:

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

    r7e752b2 rcd22764  
    3232
    3333/** @file
    34  * Network echo application.
    35  * Answers received packets.
     34 * Network echo server.
     35 *
     36 * Sockets-based server that echoes incomming messages. If stream mode
     37 * is selected, accepts incoming connections.
    3638 */
    3739
    38 #include <malloc.h>
     40#include <assert.h>
    3941#include <stdio.h>
     42#include <stdlib.h>
    4043#include <str.h>
    4144#include <task.h>
     
    5053#include "print_error.h"
    5154
    52 /** Network echo module name. */
    53 #define NAME    "Network Echo"
     55#define NAME "netecho"
     56
     57static int count = -1;
     58static int family = PF_INET;
     59static sock_type_t type = SOCK_DGRAM;
     60static uint16_t port = 7;
     61static int backlog = 3;
     62static size_t size = 1024;
     63static int verbose = 0;
     64
     65static char *reply = NULL;
     66static size_t reply_length;
     67
     68static char *data;
    5469
    5570static void echo_print_help(void)
    5671{
    5772        printf(
    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"
     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"
    87109        );
    88110}
    89111
    90 int main(int argc, char *argv[])
     112static int netecho_parse_option(int argc, char *argv[], int *index)
    91113{
    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;
    115114        int value;
    116115        int rc;
    117116
    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                         }
     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;
    214205                } else {
    215206                        echo_print_help();
    216207                        return EINVAL;
    217208                }
    218         }
    219 
    220         // check the buffer size
     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 */
     223static 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
     317int 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 */
    221341        if (size <= 0) {
    222342                fprintf(stderr, "Receive size too small (%zu). Using 1024 bytes instead.\n", size);
    223343                size = 1024;
    224344        }
    225         // size plus the terminating null (\0)
     345
     346        /* size plus the terminating null character. */
    226347        data = (char *) malloc(size + 1);
    227348        if (!data) {
     
    230351        }
    231352
    232         // set the reply size if set
     353        /* Set the reply size if set */
    233354        reply_length = reply ? str_length(reply) : 0;
    234355
    235         // prepare the address buffer
    236         bzero(address_data, max_length);
     356        /* Prepare the address buffer */
    237357        switch (family) {
    238358        case PF_INET:
    239                 address_in->sin_family = AF_INET;
    240                 address_in->sin_port = htons(port);
    241                 addrlen = sizeof(struct sockaddr_in);
     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);
    242363                break;
    243364        case PF_INET6:
    244                 address_in6->sin6_family = AF_INET6;
    245                 address_in6->sin6_port = htons(port);
    246                 addrlen = sizeof(struct sockaddr_in6);
     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);
    247369                break;
    248370        default:
     
    251373        }
    252374
    253         // get a listening socket
     375        /* Get a listening socket */
    254376        listening_id = socket(family, type, 0);
    255377        if (listening_id < 0) {
     
    258380        }
    259381
    260         // if the stream socket is used
     382        /* if the stream socket is used */
    261383        if (type == SOCK_STREAM) {
    262                 // check the backlog
     384                /* Check backlog size */
    263385                if (backlog <= 0) {
    264386                        fprintf(stderr, "Accepted sockets queue size too small (%zu). Using 3 instead.\n", size);
    265387                        backlog = 3;
    266388                }
    267                 // set the backlog
     389
     390                /* Set the backlog */
    268391                rc = listen(listening_id, backlog);
    269392                if (rc != EOK) {
     
    273396        }
    274397
    275         // bind the listenning socket
     398        /* Bind the listening socket */
    276399        rc = bind(listening_id, address, addrlen);
    277400        if (rc != EOK) {
     
    283406                printf("Socket %d listenning at %d\n", listening_id, port);
    284407
    285         socket_id = listening_id;
    286 
    287         // do count times
    288         // or indefinitely if set to a negative value
     408        /*
     409         * do count times
     410         * or indefinitely if set to a negative value
     411         */
    289412        while (count) {
    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
     413                rc = netecho_socket_process_message(listening_id);
     414                if (rc != EOK)
     415                        break;
     416
     417                /* Decrease count if positive */
    359418                if (count > 0) {
    360419                        count--;
    361420                        if (verbose)
    362                                 printf("Waiting for next %d packet(s)\n", count);
     421                                printf("Waiting for next %d message(s)\n", count);
    363422                }
    364423        }
     
    367426                printf("Closing the socket\n");
    368427
    369         // close the listenning socket
     428        /* Close listenning socket */
    370429        rc = closesocket(listening_id);
    371430        if (rc != EOK) {
Note: See TracChangeset for help on using the changeset viewer.