Ignore:
File:
1 edited

Legend:

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

    rccdc63e r3e6a98c5  
    11/*
    2  * Copyright (c) 2013 Jiri Svoboda
     2 * Copyright (c) 2012 Jiri Svoboda
    33 * All rights reserved.
    44 *
     
    3737#include <errno.h>
    3838#include <fibril_synch.h>
    39 #include <net/socket_codes.h>
    40 #include <inet/dnsr.h>
    41 #include <inet/addr.h>
    4239#include <inet/inetping.h>
    4340#include <io/console.h>
    44 #include <getopt.h>
    4541#include <stdio.h>
    4642#include <stdlib.h>
    47 #include <str.h>
    48 #include <str_error.h>
    4943#include <sys/types.h>
    5044
     
    5751#define PING_TIMEOUT (1000 * 1000)
    5852
    59 typedef enum {
    60         RECEIVED_NONE,
    61         RECEIVED_SUCCESS,
    62         RECEIVED_INTERRUPT
    63 } received_t;
    64 
    65 static received_t received;
    66 static FIBRIL_CONDVAR_INITIALIZE(received_cv);
    67 static FIBRIL_MUTEX_INITIALIZE(received_lock);
    68 
    69 static bool quit = false;
    70 static FIBRIL_CONDVAR_INITIALIZE(quit_cv);
    71 static FIBRIL_MUTEX_INITIALIZE(quit_lock);
    72 
    7353static int ping_ev_recv(inetping_sdu_t *);
     54
     55static bool done = false;
     56static FIBRIL_CONDVAR_INITIALIZE(done_cv);
     57static FIBRIL_MUTEX_INITIALIZE(done_lock);
    7458
    7559static inetping_ev_ops_t ev_ops = {
     
    7761};
    7862
    79 static addr32_t src;
    80 static addr32_t dest;
    81 
    82 static bool repeat_forever = false;
    83 static size_t repeat_count = 1;
    84 
    85 static const char *short_options = "rn:";
     63static inet_addr_t src_addr;
     64static inet_addr_t dest_addr;
     65
     66static bool ping_repeat = false;
    8667
    8768static void print_syntax(void)
    8869{
    89         printf("Syntax: %s [-n <count>|-r] <host>\n", NAME);
    90 }
    91 
    92 static 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 
    100 static 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);
     70        printf("syntax: " NAME " [-r] <addr>\n");
     71}
     72
     73static int addr_parse(const char *text, inet_addr_t *addr)
     74{
     75        unsigned long a[4];
     76        char *cp = (char *)text;
     77        int i;
     78
     79        for (i = 0; i < 3; i++) {
     80                a[i] = strtoul(cp, &cp, 10);
     81                if (*cp != '.')
     82                        return EINVAL;
     83                ++cp;
     84        }
     85
     86        a[3] = strtoul(cp, &cp, 10);
     87        if (*cp != '\0')
     88                return EINVAL;
     89
     90        addr->ipv4 = 0;
     91        for (i = 0; i < 4; i++) {
     92                if (a[i] > 255)
     93                        return EINVAL;
     94                addr->ipv4 = (addr->ipv4 << 8) | a[i];
     95        }
     96
     97        return EOK;
     98}
     99
     100static int addr_format(inet_addr_t *addr, char **bufp)
     101{
     102        int rc;
     103
     104        rc = asprintf(bufp, "%d.%d.%d.%d", addr->ipv4 >> 24,
     105            (addr->ipv4 >> 16) & 0xff, (addr->ipv4 >> 8) & 0xff,
     106            addr->ipv4 & 0xff);
     107
     108        if (rc < 0)
     109                return ENOMEM;
     110
     111        return EOK;
     112}
     113
     114static void ping_signal_done(void)
     115{
     116        fibril_mutex_lock(&done_lock);
     117        done = true;
     118        fibril_mutex_unlock(&done_lock);
     119        fibril_condvar_broadcast(&done_cv);
    106120}
    107121
    108122static int ping_ev_recv(inetping_sdu_t *sdu)
    109123{
    110         inet_addr_t src_addr;
    111         inet_addr_set(sdu->src, &src_addr);
    112        
    113         inet_addr_t dest_addr;
    114         inet_addr_set(sdu->dest, &dest_addr);
    115        
    116         char *asrc;
    117         int rc = inet_addr_format(&src_addr, &asrc);
     124        char *asrc, *adest;
     125        int rc;
     126
     127        rc = addr_format(&sdu->src, &asrc);
    118128        if (rc != EOK)
    119129                return ENOMEM;
    120        
    121         char *adest;
    122         rc = inet_addr_format(&dest_addr, &adest);
     130
     131        rc = addr_format(&sdu->dest, &adest);
    123132        if (rc != EOK) {
    124133                free(asrc);
    125134                return ENOMEM;
    126135        }
    127        
    128136        printf("Received ICMP echo reply: from %s to %s, seq. no %u, "
    129137            "payload size %zu\n", asrc, adest, sdu->seq_no, sdu->size);
    130        
    131         ping_signal_received(RECEIVED_SUCCESS);
    132        
     138
     139        if (!ping_repeat) {
     140                ping_signal_done();
     141        }
     142
    133143        free(asrc);
    134144        free(adest);
     
    139149{
    140150        inetping_sdu_t sdu;
    141        
    142         sdu.src = src;
    143         sdu.dest = dest;
     151        int rc;
     152
     153        sdu.src = src_addr;
     154        sdu.dest = dest_addr;
    144155        sdu.seq_no = seq_no;
    145156        sdu.data = (void *) "foo";
    146157        sdu.size = 3;
    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;
     158
     159        rc = inetping_send(&sdu);
     160        if (rc != EOK) {
     161                printf(NAME ": Failed sending echo request (%d).\n", rc);
     162                return rc;
     163        }
     164
     165        return EOK;
    154166}
    155167
     
    157169{
    158170        uint16_t seq_no = 0;
    159        
    160         while ((repeat_count--) || (repeat_forever)) {
    161                 fibril_mutex_lock(&received_lock);
    162                 received = RECEIVED_NONE;
    163                 fibril_mutex_unlock(&received_lock);
    164                
     171
     172        while (true) {
     173                fibril_mutex_lock(&done_lock);
     174                if (done) {
     175                        fibril_mutex_unlock(&done_lock);
     176                        return 0;
     177                }
     178                fibril_mutex_unlock(&done_lock);
     179
    165180                (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)
     181                async_usleep(PING_DELAY);
     182        }
     183
     184        return 0;
     185}
     186
     187static int input_fibril(void *arg)
     188{
     189        console_ctrl_t *con;
     190        kbd_event_t ev;
     191
     192        con = console_init(stdin, stdout);
     193        printf("[Press Ctrl-Q to quit]\n");
     194
     195        while (true) {
     196                if (!console_get_kbd_event(con, &ev))
    177197                        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();
     198
     199                if (ev.type == KEY_PRESS && (ev.mods & (KM_ALT | KM_SHIFT)) ==
     200                    0 && (ev.mods & KM_CTRL) != 0) {
     201                        /* Ctrl+key */
     202                        if (ev.key == KC_Q) {
     203                                ping_signal_done();
     204                                return 0;
     205                        }
     206                }
     207        }
     208
    192209        return 0;
    193210}
    194211
    195 static int input_fibril(void *arg)
    196 {
    197         console_ctrl_t *con = console_init(stdin, stdout);
    198        
    199         while (true) {
    200                 cons_event_t ev;
    201                 if (!console_get_event(con, &ev))
    202                         break;
    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)) {
    207                         /* Ctrl+key */
    208                         if (ev.ev.key.key == KC_Q) {
    209                                 ping_signal_received(RECEIVED_INTERRUPT);
    210                                 break;
    211                         }
    212                 }
    213         }
    214        
     212int main(int argc, char *argv[])
     213{
     214        int rc;
     215        int argi;
     216
     217        rc = inetping_init(&ev_ops);
     218        if (rc != EOK) {
     219                printf(NAME ": Failed connecting to internet ping service "
     220                    "(%d).\n", rc);
     221                return 1;
     222        }
     223
     224        argi = 1;
     225        if (argi < argc && str_cmp(argv[argi], "-r") == 0) {
     226                ping_repeat = true;
     227                ++argi;
     228        } else {
     229                ping_repeat = false;
     230        }
     231
     232        if (argc - argi != 1) {
     233                print_syntax();
     234                return 1;
     235        }
     236
     237        /* Parse destination address */
     238        rc = addr_parse(argv[argi], &dest_addr);
     239        if (rc != EOK) {
     240                printf(NAME ": Invalid address format.\n");
     241                print_syntax();
     242                return 1;
     243        }
     244
     245        /* Determine source address */
     246        rc = inetping_get_srcaddr(&dest_addr, &src_addr);
     247        if (rc != EOK) {
     248                printf(NAME ": Failed determining source address.\n");
     249                return 1;
     250        }
     251
     252        fid_t fid;
     253
     254        if (ping_repeat) {
     255                fid = fibril_create(transmit_fibril, NULL);
     256                if (fid == 0) {
     257                        printf(NAME ": Failed creating transmit fibril.\n");
     258                        return 1;
     259                }
     260
     261                fibril_add_ready(fid);
     262
     263                fid = fibril_create(input_fibril, NULL);
     264                if (fid == 0) {
     265                        printf(NAME ": Failed creating input fibril.\n");
     266                        return 1;
     267                }
     268
     269                fibril_add_ready(fid);
     270        } else {
     271                ping_send(1);
     272        }
     273
     274        fibril_mutex_lock(&done_lock);
     275        rc = EOK;
     276        while (!done && rc != ETIMEOUT) {
     277                rc = fibril_condvar_wait_timeout(&done_cv, &done_lock,
     278                        ping_repeat ? 0 : PING_TIMEOUT);
     279        }
     280        fibril_mutex_unlock(&done_lock);
     281
     282        if (rc == ETIMEOUT) {
     283                printf(NAME ": Echo request timed out.\n");
     284                return 1;
     285        }
     286
    215287        return 0;
    216288}
    217289
    218 int main(int argc, char *argv[])
    219 {
    220         dnsr_hostinfo_t *hinfo = NULL;
    221         char *asrc = NULL;
    222         char *adest = NULL;
    223         char *sdest = NULL;
    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");
    255                 print_syntax();
    256                 goto error;
    257         }
    258        
    259         /* Parse destination address */
    260         inet_addr_t dest_addr;
    261         rc = inet_addr_parse(argv[optind], &dest_addr);
    262         if (rc != EOK) {
    263                 /* Try interpreting as a host name */
    264                 rc = dnsr_name2host(argv[optind], &hinfo, AF_INET);
    265                 if (rc != EOK) {
    266                         printf("Error resolving host '%s'.\n", argv[optind]);
    267                         goto error;
    268                 }
    269                
    270                 dest_addr = hinfo->addr;
    271         }
    272        
    273         uint16_t af = inet_addr_get(&dest_addr, &dest, NULL);
    274         if (af != AF_INET) {
    275                 printf("Destination '%s' is not an IPv4 address.\n",
    276                     argv[optind]);
    277                 goto error;
    278         }
    279        
    280         /* Determine source address */
    281         rc = inetping_get_srcaddr(dest, &src);
    282         if (rc != EOK) {
    283                 printf("Failed determining source address.\n");
    284                 goto error;
    285         }
    286        
    287         inet_addr_t src_addr;
    288         inet_addr_set(src, &src_addr);
    289        
    290         rc = inet_addr_format(&src_addr, &asrc);
    291         if (rc != EOK) {
    292                 printf("Out of memory.\n");
    293                 goto error;
    294         }
    295        
    296         rc = inet_addr_format(&dest_addr, &adest);
    297         if (rc != EOK) {
    298                 printf("Out of memory.\n");
    299                 goto error;
    300         }
    301        
    302         if (hinfo != NULL) {
    303                 rc = asprintf(&sdest, "%s (%s)", hinfo->cname, adest);
    304                 if (rc < 0) {
    305                         printf("Out of memory.\n");
    306                         goto error;
    307                 }
    308         } else {
    309                 sdest = adest;
    310                 adest = NULL;
    311         }
    312        
    313         printf("Sending ICMP echo request from %s to %s (Ctrl+Q to quit)\n",
    314             asrc, sdest);
    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        
    337         free(asrc);
    338         free(adest);
    339         free(sdest);
    340         dnsr_hostinfo_destroy(hinfo);
    341         return 0;
    342        
    343 error:
    344         free(asrc);
    345         free(adest);
    346         free(sdest);
    347         dnsr_hostinfo_destroy(hinfo);
    348         return 1;
    349 }
    350 
    351290/** @}
    352291 */
Note: See TracChangeset for help on using the changeset viewer.