Ignore:
File:
1 edited

Legend:

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

    r3e6a98c5 rccdc63e  
    11/*
    2  * Copyright (c) 2012 Jiri Svoboda
     2 * Copyright (c) 2013 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>
    3942#include <inet/inetping.h>
    4043#include <io/console.h>
     44#include <getopt.h>
    4145#include <stdio.h>
    4246#include <stdlib.h>
     47#include <str.h>
     48#include <str_error.h>
    4349#include <sys/types.h>
    4450
     
    5157#define PING_TIMEOUT (1000 * 1000)
    5258
     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
    5373static int ping_ev_recv(inetping_sdu_t *);
    54 
    55 static bool done = false;
    56 static FIBRIL_CONDVAR_INITIALIZE(done_cv);
    57 static FIBRIL_MUTEX_INITIALIZE(done_lock);
    5874
    5975static inetping_ev_ops_t ev_ops = {
     
    6177};
    6278
    63 static inet_addr_t src_addr;
    64 static inet_addr_t dest_addr;
    65 
    66 static bool ping_repeat = false;
     79static addr32_t src;
     80static addr32_t dest;
     81
     82static bool repeat_forever = false;
     83static size_t repeat_count = 1;
     84
     85static const char *short_options = "rn:";
    6786
    6887static void print_syntax(void)
    6988{
    70         printf("syntax: " NAME " [-r] <addr>\n");
    71 }
    72 
    73 static 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 
    100 static 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 
    114 static 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);
     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);
    120106}
    121107
    122108static int ping_ev_recv(inetping_sdu_t *sdu)
    123109{
    124         char *asrc, *adest;
    125         int rc;
    126 
    127         rc = addr_format(&sdu->src, &asrc);
     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);
    128118        if (rc != EOK)
    129119                return ENOMEM;
    130 
    131         rc = addr_format(&sdu->dest, &adest);
     120       
     121        char *adest;
     122        rc = inet_addr_format(&dest_addr, &adest);
    132123        if (rc != EOK) {
    133124                free(asrc);
    134125                return ENOMEM;
    135126        }
     127       
    136128        printf("Received ICMP echo reply: from %s to %s, seq. no %u, "
    137129            "payload size %zu\n", asrc, adest, sdu->seq_no, sdu->size);
    138 
    139         if (!ping_repeat) {
    140                 ping_signal_done();
    141         }
    142 
     130       
     131        ping_signal_received(RECEIVED_SUCCESS);
     132       
    143133        free(asrc);
    144134        free(adest);
     
    149139{
    150140        inetping_sdu_t sdu;
    151         int rc;
    152 
    153         sdu.src = src_addr;
    154         sdu.dest = dest_addr;
     141       
     142        sdu.src = src;
     143        sdu.dest = dest;
    155144        sdu.seq_no = seq_no;
    156145        sdu.data = (void *) "foo";
    157146        sdu.size = 3;
    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;
     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;
    166154}
    167155
     
    169157{
    170158        uint16_t seq_no = 0;
    171 
     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       
    172199        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 
    180                 (void) ping_send(++seq_no);
    181                 async_usleep(PING_DELAY);
    182         }
    183 
     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       
    184215        return 0;
    185216}
    186217
    187 static 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))
     218int 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;
    197237                        break;
    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;
     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;
    205244                        }
    206                 }
    207         }
    208 
     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);
    209341        return 0;
    210 }
    211 
    212 int 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 
    287         return 0;
     342       
     343error:
     344        free(asrc);
     345        free(adest);
     346        free(sdest);
     347        dnsr_hostinfo_destroy(hinfo);
     348        return 1;
    288349}
    289350
Note: See TracChangeset for help on using the changeset viewer.