Changeset ccdc63e in mainline for uspace/app/ping/ping.c


Ignore:
Timestamp:
2013-07-25T19:35:54Z (11 years ago)
Author:
Martin Decky <martin@…>
Branches:
lfn, master, serial, ticket/834-toolchain-update, topic/msim-upgrade, topic/simplify-dev-export
Children:
e3480d5, e3bc355, f94b24c8
Parents:
83781a22
Message:

handle timeouts properly in the repeated (-r) ping mode (this fixes #457)
add the -n option
based on the original patch by Jakub Klama

File:
1 edited

Legend:

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

    r83781a22 rccdc63e  
    4242#include <inet/inetping.h>
    4343#include <io/console.h>
     44#include <getopt.h>
    4445#include <stdio.h>
    4546#include <stdlib.h>
     47#include <str.h>
     48#include <str_error.h>
    4649#include <sys/types.h>
    4750
     
    5457#define PING_TIMEOUT (1000 * 1000)
    5558
     59typedef enum {
     60        RECEIVED_NONE,
     61        RECEIVED_SUCCESS,
     62        RECEIVED_INTERRUPT
     63} received_t;
     64
     65static received_t received;
     66static FIBRIL_CONDVAR_INITIALIZE(received_cv);
     67static FIBRIL_MUTEX_INITIALIZE(received_lock);
     68
     69static bool quit = false;
     70static FIBRIL_CONDVAR_INITIALIZE(quit_cv);
     71static FIBRIL_MUTEX_INITIALIZE(quit_lock);
     72
    5673static int ping_ev_recv(inetping_sdu_t *);
    57 
    58 static bool done = false;
    59 static FIBRIL_CONDVAR_INITIALIZE(done_cv);
    60 static FIBRIL_MUTEX_INITIALIZE(done_lock);
    6174
    6275static inetping_ev_ops_t ev_ops = {
     
    6780static addr32_t dest;
    6881
    69 static bool ping_repeat = false;
     82static bool repeat_forever = false;
     83static size_t repeat_count = 1;
     84
     85static const char *short_options = "rn:";
    7086
    7187static void print_syntax(void)
    7288{
    73         printf("syntax: " NAME " [-r] <host>\n");
    74 }
    75 
    76 static void ping_signal_done(void)
    77 {
    78         fibril_mutex_lock(&done_lock);
    79         done = true;
    80         fibril_mutex_unlock(&done_lock);
    81         fibril_condvar_broadcast(&done_cv);
     89        printf("Syntax: %s [-n <count>|-r] <host>\n", NAME);
     90}
     91
     92static void ping_signal_received(received_t value)
     93{
     94        fibril_mutex_lock(&received_lock);
     95        received = value;
     96        fibril_mutex_unlock(&received_lock);
     97        fibril_condvar_broadcast(&received_cv);
     98}
     99
     100static void ping_signal_quit(void)
     101{
     102        fibril_mutex_lock(&quit_lock);
     103        quit = true;
     104        fibril_mutex_unlock(&quit_lock);
     105        fibril_condvar_broadcast(&quit_cv);
    82106}
    83107
     
    105129            "payload size %zu\n", asrc, adest, sdu->seq_no, sdu->size);
    106130       
    107         if (!ping_repeat)
    108                 ping_signal_done();
     131        ping_signal_received(RECEIVED_SUCCESS);
    109132       
    110133        free(asrc);
     
    116139{
    117140        inetping_sdu_t sdu;
    118         int rc;
    119 
     141       
    120142        sdu.src = src;
    121143        sdu.dest = dest;
     
    123145        sdu.data = (void *) "foo";
    124146        sdu.size = 3;
    125 
    126         rc = inetping_send(&sdu);
    127         if (rc != EOK) {
    128                 printf(NAME ": Failed sending echo request (%d).\n", rc);
    129                 return rc;
    130         }
    131 
    132         return EOK;
     147       
     148        int rc = inetping_send(&sdu);
     149        if (rc != EOK)
     150                printf("Failed sending echo request: %s (%d).\n",
     151                    str_error(rc), rc);
     152       
     153        return rc;
    133154}
    134155
     
    136157{
    137158        uint16_t seq_no = 0;
    138 
     159       
     160        while ((repeat_count--) || (repeat_forever)) {
     161                fibril_mutex_lock(&received_lock);
     162                received = RECEIVED_NONE;
     163                fibril_mutex_unlock(&received_lock);
     164               
     165                (void) ping_send(++seq_no);
     166               
     167                fibril_mutex_lock(&received_lock);
     168                int rc = fibril_condvar_wait_timeout(&received_cv, &received_lock,
     169                    PING_TIMEOUT);
     170                received_t recv = received;
     171                fibril_mutex_unlock(&received_lock);
     172               
     173                if ((rc == ETIMEOUT) || (recv == RECEIVED_NONE))
     174                        printf("Echo request timed out (seq. no %u)\n", seq_no);
     175               
     176                if (recv == RECEIVED_INTERRUPT)
     177                        break;
     178               
     179                if ((repeat_count > 0) || (repeat_forever)) {
     180                        fibril_mutex_lock(&received_lock);
     181                        rc = fibril_condvar_wait_timeout(&received_cv, &received_lock,
     182                            PING_DELAY);
     183                        recv = received;
     184                        fibril_mutex_unlock(&received_lock);
     185                       
     186                        if (recv == RECEIVED_INTERRUPT)
     187                                break;
     188                }
     189        }
     190       
     191        ping_signal_quit();
     192        return 0;
     193}
     194
     195static int input_fibril(void *arg)
     196{
     197        console_ctrl_t *con = console_init(stdin, stdout);
     198       
    139199        while (true) {
    140                 fibril_mutex_lock(&done_lock);
    141                 if (done) {
    142                         fibril_mutex_unlock(&done_lock);
    143                         return 0;
    144                 }
    145                 fibril_mutex_unlock(&done_lock);
    146 
    147                 (void) ping_send(++seq_no);
    148                 async_usleep(PING_DELAY);
    149         }
    150 
    151         return 0;
    152 }
    153 
    154 static int input_fibril(void *arg)
    155 {
    156         console_ctrl_t *con;
    157         cons_event_t ev;
    158 
    159         con = console_init(stdin, stdout);
    160         printf("[Press Ctrl-Q to quit]\n");
    161 
    162         while (true) {
     200                cons_event_t ev;
    163201                if (!console_get_event(con, &ev))
    164202                        break;
    165 
    166                 if (ev.type == CEV_KEY && ev.ev.key.type == KEY_PRESS &&
    167                     (ev.ev.key.mods & (KM_ALT | KM_SHIFT)) ==
    168                     0 && (ev.ev.key.mods & KM_CTRL) != 0) {
     203               
     204                if ((ev.type == CEV_KEY) && (ev.ev.key.type == KEY_PRESS) &&
     205                    ((ev.ev.key.mods & (KM_ALT | KM_SHIFT)) == 0) &&
     206                    ((ev.ev.key.mods & KM_CTRL) != 0)) {
    169207                        /* Ctrl+key */
    170208                        if (ev.ev.key.key == KC_Q) {
    171                                 ping_signal_done();
    172                                 return 0;
     209                                ping_signal_received(RECEIVED_INTERRUPT);
     210                                break;
    173211                        }
    174212                }
    175213        }
    176 
     214       
    177215        return 0;
    178216}
     
    184222        char *adest = NULL;
    185223        char *sdest = NULL;
    186         int rc;
    187         int argi;
    188 
    189         rc = inetping_init(&ev_ops);
    190         if (rc != EOK) {
    191                 printf(NAME ": Failed connecting to internet ping service "
    192                     "(%d).\n", rc);
    193                 goto error;
    194         }
    195 
    196         argi = 1;
    197         if (argi < argc && str_cmp(argv[argi], "-r") == 0) {
    198                 ping_repeat = true;
    199                 ++argi;
    200         } else {
    201                 ping_repeat = false;
    202         }
    203 
    204         if (argc - argi != 1) {
     224       
     225        int rc = inetping_init(&ev_ops);
     226        if (rc != EOK) {
     227                printf("Failed connecting to internet ping service: "
     228                    "%s (%d).\n", str_error(rc), rc);
     229                goto error;
     230        }
     231       
     232        int c;
     233        while ((c = getopt(argc, argv, short_options)) != -1) {
     234                switch (c) {
     235                case 'r':
     236                        repeat_forever = true;
     237                        break;
     238                case 'n':
     239                        rc = str_size_t(optarg, NULL, 10, true, &repeat_count);
     240                        if (rc != EOK) {
     241                                printf("Invalid repeat count.\n");
     242                                print_syntax();
     243                                goto error;
     244                        }
     245                        break;
     246                default:
     247                        printf("Unknown option passed.\n");
     248                        print_syntax();
     249                        goto error;
     250                }
     251        }
     252       
     253        if (optind >= argc) {
     254                printf("IP address or host name not supplied.\n");
    205255                print_syntax();
    206256                goto error;
    207257        }
    208 
     258       
    209259        /* Parse destination address */
    210260        inet_addr_t dest_addr;
    211         rc = inet_addr_parse(argv[argi], &dest_addr);
     261        rc = inet_addr_parse(argv[optind], &dest_addr);
    212262        if (rc != EOK) {
    213263                /* Try interpreting as a host name */
    214                 rc = dnsr_name2host(argv[argi], &hinfo, AF_INET);
     264                rc = dnsr_name2host(argv[optind], &hinfo, AF_INET);
    215265                if (rc != EOK) {
    216                         printf(NAME ": Error resolving host '%s'.\n", argv[argi]);
     266                        printf("Error resolving host '%s'.\n", argv[optind]);
    217267                        goto error;
    218268                }
     
    223273        uint16_t af = inet_addr_get(&dest_addr, &dest, NULL);
    224274        if (af != AF_INET) {
    225                 printf(NAME ": Destination '%s' is not an IPv4 address.\n",
    226                     argv[argi]);
     275                printf("Destination '%s' is not an IPv4 address.\n",
     276                    argv[optind]);
    227277                goto error;
    228278        }
     
    231281        rc = inetping_get_srcaddr(dest, &src);
    232282        if (rc != EOK) {
    233                 printf(NAME ": Failed determining source address.\n");
     283                printf("Failed determining source address.\n");
    234284                goto error;
    235285        }
     
    240290        rc = inet_addr_format(&src_addr, &asrc);
    241291        if (rc != EOK) {
    242                 printf(NAME ": Out of memory.\n");
     292                printf("Out of memory.\n");
    243293                goto error;
    244294        }
     
    246296        rc = inet_addr_format(&dest_addr, &adest);
    247297        if (rc != EOK) {
    248                 printf(NAME ": Out of memory.\n");
     298                printf("Out of memory.\n");
    249299                goto error;
    250300        }
     
    253303                rc = asprintf(&sdest, "%s (%s)", hinfo->cname, adest);
    254304                if (rc < 0) {
    255                         printf(NAME ": Out of memory.\n");
     305                        printf("Out of memory.\n");
    256306                        goto error;
    257307                }
     
    260310                adest = NULL;
    261311        }
    262 
    263         printf("Sending ICMP echo request from %s to %s.\n",
     312       
     313        printf("Sending ICMP echo request from %s to %s (Ctrl+Q to quit)\n",
    264314            asrc, sdest);
    265 
    266         fid_t fid;
    267 
    268         if (ping_repeat) {
    269                 fid = fibril_create(transmit_fibril, NULL);
    270                 if (fid == 0) {
    271                         printf(NAME ": Failed creating transmit fibril.\n");
    272                         goto error;
    273                 }
    274 
    275                 fibril_add_ready(fid);
    276 
    277                 fid = fibril_create(input_fibril, NULL);
    278                 if (fid == 0) {
    279                         printf(NAME ": Failed creating input fibril.\n");
    280                         goto error;
    281                 }
    282 
    283                 fibril_add_ready(fid);
    284         } else {
    285                 ping_send(1);
    286         }
    287 
    288         fibril_mutex_lock(&done_lock);
    289         rc = EOK;
    290         while (!done && rc != ETIMEOUT) {
    291                 rc = fibril_condvar_wait_timeout(&done_cv, &done_lock,
    292                         ping_repeat ? 0 : PING_TIMEOUT);
    293         }
    294         fibril_mutex_unlock(&done_lock);
    295 
    296         if (rc == ETIMEOUT) {
    297                 printf(NAME ": Echo request timed out.\n");
    298                 goto error;
    299         }
    300 
     315       
     316        fid_t fid = fibril_create(transmit_fibril, NULL);
     317        if (fid == 0) {
     318                printf("Failed creating transmit fibril.\n");
     319                goto error;
     320        }
     321       
     322        fibril_add_ready(fid);
     323       
     324        fid = fibril_create(input_fibril, NULL);
     325        if (fid == 0) {
     326                printf("Failed creating input fibril.\n");
     327                goto error;
     328        }
     329       
     330        fibril_add_ready(fid);
     331       
     332        fibril_mutex_lock(&quit_lock);
     333        while (!quit)
     334                fibril_condvar_wait(&quit_cv, &quit_lock);
     335        fibril_mutex_unlock(&quit_lock);
     336       
    301337        free(asrc);
    302338        free(adest);
Note: See TracChangeset for help on using the changeset viewer.