Subversion Repositories Kolibri OS

Rev

Rev 6029 | Rev 7891 | Go to most recent revision | Details | Compare with Previous | Last modification | View Log | RSS feed

Rev Author Line No. Line
3545 hidnplayr 1
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
2
;;                                                                 ;;
5805 hidnplayr 3
;; Copyright (C) KolibriOS team 2010-2015. All rights reserved.    ;;
3545 hidnplayr 4
;; Distributed under terms of the GNU General Public License       ;;
5
;;                                                                 ;;
6
;;  ping.asm - ICMP echo client for KolibriOS                      ;;
7
;;                                                                 ;;
8
;;  Written by hidnplayr@kolibrios.org                             ;;
9
;;                                                                 ;;
10
;;          GNU GENERAL PUBLIC LICENSE                             ;;
11
;;             Version 2, June 1991                                ;;
12
;;                                                                 ;;
13
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
14
 
15
format binary as ""
16
 
3618 hidnplayr 17
BUFFERSIZE      = 1500
4012 hidnplayr 18
IDENTIFIER      = 0x1337
3618 hidnplayr 19
 
3545 hidnplayr 20
use32
21
        org     0x0
22
 
23
        db      'MENUET01'      ; signature
24
        dd      1               ; header version
5805 hidnplayr 25
        dd      START           ; entry point
3545 hidnplayr 26
        dd      I_END           ; initialized size
5805 hidnplayr 27
        dd      IM_END+0x1000   ; required memory
28
        dd      IM_END+0x1000   ; stack pointer
5842 hidnplayr 29
        dd      params          ; parameters
3545 hidnplayr 30
        dd      0               ; path
31
 
5805 hidnplayr 32
include '../../proc32.inc'
3618 hidnplayr 33
include '../../macros.inc'
3545 hidnplayr 34
purge mov,add,sub
3618 hidnplayr 35
include '../../dll.inc'
5842 hidnplayr 36
include '../../struct.inc'
3618 hidnplayr 37
include '../../network.inc'
3545 hidnplayr 38
 
6477 hidnplayr 39
include '../icmp.inc'
40
include '../ip.inc'
3545 hidnplayr 41
 
42
 
5805 hidnplayr 43
START:
44
; init heap
45
        mcall   68, 11
46
        test    eax, eax
47
        jz      exit
3545 hidnplayr 48
; load libraries
49
        stdcall dll.Load, @IMPORT
50
        test    eax, eax
51
        jnz     exit
52
; initialize console
53
        push    1
54
        call    [con_start]
55
        push    title
5842 hidnplayr 56
        push    250
3545 hidnplayr 57
        push    80
58
        push    25
59
        push    80
60
        call    [con_init]
5842 hidnplayr 61
; expand payload to 65504 bytes
62
        mov     edi, icmp_packet.data+32
63
        mov     ecx, 65504/32-1
64
  .expand_payload:
65
        mov     esi, icmp_packet.data
66
        movsd
67
        movsd
68
        movsd
69
        movsd
70
        movsd
71
        movsd
72
        movsd
73
        movsd
74
        dec     ecx
75
        jnz     .expand_payload
3545 hidnplayr 76
; main loop
5842 hidnplayr 77
        cmp     byte[params], 0
5249 hidnplayr 78
        jne     parse_param
4019 hidnplayr 79
 
80
        push    str_welcome
81
        call    [con_write_asciiz]
3545 hidnplayr 82
main:
83
; write prompt
4019 hidnplayr 84
        push    str_prompt
3545 hidnplayr 85
        call    [con_write_asciiz]
86
; read string
5842 hidnplayr 87
        mov     esi, params
88
        push    1024
3545 hidnplayr 89
        push    esi
90
        call    [con_gets]
91
; check for exit
92
        test    eax, eax
4024 hidnplayr 93
        jz      exit
3545 hidnplayr 94
        cmp     byte [esi], 10
4024 hidnplayr 95
        jz      exit
3545 hidnplayr 96
; delete terminating '\n'
97
        push    esi
98
@@:
99
        lodsb
100
        test    al, al
101
        jnz     @b
5805 hidnplayr 102
        mov     [esi-2], al
3545 hidnplayr 103
        pop     esi
104
 
4019 hidnplayr 105
; reset stats
106
        mov     [stats.tx], 0
107
        mov     [stats.rx], 0
108
        mov     [stats.time], 0
109
 
5249 hidnplayr 110
parse_param:
5842 hidnplayr 111
; parameters defaults
112
        mov     [count], 4
113
        mov     [size], 32
114
        mov     [ttl], 128
115
        mov     [timeout], 300
5249 hidnplayr 116
 
117
; Check if any additional parameters were given
5842 hidnplayr 118
        mov     esi, params
5249 hidnplayr 119
        mov     ecx, 1024
120
  .addrloop:
121
        lodsb
122
        test    al, al
123
        jz      .resolve
124
        cmp     al, ' '
125
        jne     .addrloop
126
        mov     byte[esi-1], 0
127
        jmp     .param
128
 
129
  .param_loop:
130
        lodsb
131
        test    al, al
132
        jz      .resolve
133
        cmp     al, ' '
134
        jne     .invalid
135
  .param:
136
        lodsb
137
        cmp     al, '-'
138
        jne     .invalid
139
        lodsb
140
        cmp     al, 't'
141
        jne     @f
142
        mov     [count], -1     ; infinite
143
        jmp     .param_loop
144
  @@:
5842 hidnplayr 145
        cmp     al, 'n'
146
        jne     @f
147
        call    ascii_to_dec
148
        test    ebx, ebx
149
        jz      .invalid
150
        mov     [count], ebx
151
        jmp     .param_loop
152
  @@:
153
        cmp     al, 'l'
154
        jne     @f
155
        call    ascii_to_dec
156
        test    ebx, ebx
157
        jz      .invalid
158
        cmp     ebx, 65500
159
        ja      .invalid
160
        mov     [size], ebx
161
        jmp     .param_loop
162
  @@:
163
        cmp     al, 'i'
164
        jne     @f
165
        call    ascii_to_dec
166
        test    ebx, ebx
167
        jz      .invalid
168
        cmp     ebx, 255
169
        ja      .invalid
170
        mov     [ttl], ebx
171
        jmp     .param_loop
172
  @@:
173
        cmp     al, 'w'
174
        jne     @f
175
        call    ascii_to_dec
176
        test    ebx, ebx
177
        jz      .invalid
178
        mov     [timeout], ebx
179
        jmp     .param_loop
180
  @@:
5249 hidnplayr 181
        ; implement more parameters here
182
  .invalid:
183
        push    str13
184
        call    [con_write_asciiz]
185
        jmp     main
186
 
187
  .resolve:
3545 hidnplayr 188
; resolve name
189
        push    esp     ; reserve stack place
190
        push    esp     ; fourth parameter
191
        push    0       ; third parameter
192
        push    0       ; second parameter
5842 hidnplayr 193
        push    params  ; first parameter
3545 hidnplayr 194
        call    [getaddrinfo]
195
        pop     esi
196
; test for error
197
        test    eax, eax
198
        jnz     fail
199
 
200
; convert IP address to decimal notation
201
        mov     eax, [esi+addrinfo.ai_addr]
202
        mov     eax, [eax+sockaddr_in.sin_addr]
203
        mov     [sockaddr1.ip], eax
204
        push    eax
205
        call    [inet_ntoa]
206
; write result
207
        mov     [ip_ptr], eax
208
 
209
        push    eax
210
 
211
; free allocated memory
212
        push    esi
213
        call    [freeaddrinfo]
214
 
215
        push    str4
216
        call    [con_write_asciiz]
217
 
218
        mcall   socket, AF_INET4, SOCK_RAW, IPPROTO_ICMP
219
        cmp     eax, -1
220
        jz      fail2
221
        mov     [socketnum], eax
222
 
223
        mcall   connect, [socketnum], sockaddr1, 18
5842 hidnplayr 224
        cmp     eax, -1
225
        je      fail2
3545 hidnplayr 226
 
5842 hidnplayr 227
        pushd   [ttl]
228
        pushd   4                               ; length of option
229
        pushd   IP_TTL
230
        pushd   IPPROTO_IP
231
        mcall   setsockopt, [socketnum], esp
232
        add     esp, 16
233
        cmp     eax, -1
234
        je      fail2
235
 
5805 hidnplayr 236
        mcall   40, EVM_STACK
3545 hidnplayr 237
 
238
        push    str3
239
        call    [con_write_asciiz]
4012 hidnplayr 240
 
3545 hidnplayr 241
        push    [ip_ptr]
242
        call    [con_write_asciiz]
243
 
5842 hidnplayr 244
        push    [size]
4012 hidnplayr 245
        push    str3b
246
        call    [con_printf]
5842 hidnplayr 247
        add     esp, 2*4
4012 hidnplayr 248
 
249
mainloop:
5249 hidnplayr 250
        call    [con_get_flags]
251
        test    eax, 0x200                      ; con window closed?
252
        jnz     exit_now
253
 
4012 hidnplayr 254
        inc     [stats.tx]
5805 hidnplayr 255
        mcall   26, 10                          ; Get high precision timer count
3545 hidnplayr 256
        mov     [time_reference], eax
5842 hidnplayr 257
        mov     esi, [size]
258
        add     esi, sizeof.ICMP_header
259
        xor     edi, edi
260
        mcall   send, [socketnum], icmp_packet
261
        cmp     eax, -1
262
        je      fail2
3545 hidnplayr 263
 
5842 hidnplayr 264
        mcall   23, [timeout]
5805 hidnplayr 265
        mcall   26, 10                          ; Get high precision timer count
4014 hidnplayr 266
        sub     eax, [time_reference]
5805 hidnplayr 267
        jz      @f
4014 hidnplayr 268
        xor     edx, edx
5805 hidnplayr 269
        mov     ebx, 100000
270
        div     ebx
271
        cmp     edx, 50000
272
        jb      @f
273
        inc     eax
274
  @@:
4014 hidnplayr 275
        mov     [time_reference], eax
3545 hidnplayr 276
 
5842 hidnplayr 277
; Receive reply
4012 hidnplayr 278
        mcall   recv, [socketnum], buffer_ptr, BUFFERSIZE, MSG_DONTWAIT
3545 hidnplayr 279
        cmp     eax, -1
280
        je      .no_response
5842 hidnplayr 281
        test    eax, eax
282
        jz      fail2
3545 hidnplayr 283
 
5842 hidnplayr 284
; IP header length
285
        movzx   esi, byte[buffer_ptr]
286
        and     esi, 0xf
287
        shl     esi, 2
288
 
289
; Check packet length
290
        sub     eax, esi
291
        sub     eax, sizeof.ICMP_header
4469 hidnplayr 292
        jb      .invalid
4012 hidnplayr 293
        mov     [recvd], eax
294
 
5842 hidnplayr 295
; make esi point to ICMP packet header
296
        add     esi, buffer_ptr
4012 hidnplayr 297
 
5842 hidnplayr 298
; we have a response, print the sender IP
299
        push    esi
300
        mov     eax, [buffer_ptr + IPv4_header.SourceAddress]
301
        rol     eax, 16
302
        movzx   ebx, ah
303
        push    ebx
304
        movzx   ebx, al
305
        push    ebx
306
        shr     eax, 16
307
        movzx   ebx, ah
308
        push    ebx
309
        movzx   ebx, al
310
        push    ebx
311
        push    str11
312
        call    [con_printf]
313
        add     esp, 5*4
314
        pop     esi
4012 hidnplayr 315
 
5842 hidnplayr 316
; What kind of response is it?
317
        cmp     [esi + ICMP_header.Type], ICMP_ECHOREPLY
318
        je      .echo_reply
319
        cmp     [esi + ICMP_header.Type], ICMP_TIMXCEED
320
        je      .ttl_exceeded
4012 hidnplayr 321
 
5842 hidnplayr 322
        jmp     .invalid
323
 
324
 
325
  .echo_reply:
326
 
327
        cmp     [esi + ICMP_header.Identifier], IDENTIFIER
328
        jne     .invalid
329
 
330
; Validate the packet
331
        add     esi, sizeof.ICMP_header
332
        mov     ecx, [size]
3545 hidnplayr 333
        mov     edi, icmp_packet.data
4012 hidnplayr 334
        repe    cmpsb
3545 hidnplayr 335
        jne     .miscomp
336
 
5842 hidnplayr 337
; update stats
338
        inc     [stats.rx]
5805 hidnplayr 339
        mov     eax, [time_reference]
5842 hidnplayr 340
        add     [stats.time], eax
341
 
342
        movzx   eax, [buffer_ptr + IPv4_header.TimeToLive]
343
        push    eax
344
        mov     eax, [time_reference]
5805 hidnplayr 345
        xor     edx, edx
346
        mov     ebx, 10
347
        div     ebx
348
        push    edx
4012 hidnplayr 349
        push    eax
350
        push    [recvd]
351
 
3545 hidnplayr 352
        push    str7
353
        call    [con_printf]
5842 hidnplayr 354
        add     esp, 5*4
3545 hidnplayr 355
 
4469 hidnplayr 356
        jmp     .continue
3545 hidnplayr 357
 
5842 hidnplayr 358
 
359
  .ttl_exceeded:
360
        push    str14
361
        call    [con_write_asciiz]
362
 
363
        jmp     .continue
364
 
365
 
4012 hidnplayr 366
; Error in packet, print it to user
3545 hidnplayr 367
  .miscomp:
5842 hidnplayr 368
        sub     edi, icmp_packet.data+1
3545 hidnplayr 369
        push    edi
370
        push    str9
371
        call    [con_printf]
5842 hidnplayr 372
        add     esp, 2*4
4469 hidnplayr 373
        jmp     .continue
3545 hidnplayr 374
 
4469 hidnplayr 375
; Invalid reply
376
  .invalid:
377
        push    str10
378
        call    [con_write_asciiz]
379
        jmp     .continue
380
 
4012 hidnplayr 381
; Timeout!
3545 hidnplayr 382
  .no_response:
383
        push    str8
384
        call    [con_write_asciiz]
385
 
4012 hidnplayr 386
; Send more ICMP packets ?
4469 hidnplayr 387
  .continue:
4435 hidnplayr 388
        inc     [icmp_packet.seq]
389
 
5249 hidnplayr 390
        cmp     [count], -1
391
        je      .forever
3545 hidnplayr 392
        dec     [count]
5842 hidnplayr 393
        jz      .stats
5249 hidnplayr 394
  .forever:
5842 hidnplayr 395
; wait a second before sending next request
396
        mcall   5, 100
3545 hidnplayr 397
        jmp     mainloop
398
 
5842 hidnplayr 399
; Print statistics
400
  .stats:
4019 hidnplayr 401
        cmp     [stats.rx], 0
402
        jne     @f
403
        xor     eax, eax
5805 hidnplayr 404
        xor     edx, edx
4019 hidnplayr 405
        jmp     .zero
406
  @@:
4012 hidnplayr 407
        xor     edx, edx
408
        mov     eax, [stats.time]
409
        div     [stats.rx]
5805 hidnplayr 410
        xor     edx, edx
411
        mov     ebx, 10
412
        div     ebx
4019 hidnplayr 413
  .zero:
5805 hidnplayr 414
        push    edx
4012 hidnplayr 415
        push    eax
416
        push    [stats.rx]
417
        push    [stats.tx]
418
        push    str12
419
        call    [con_printf]
5842 hidnplayr 420
        add     esp, 5*4
4019 hidnplayr 421
        jmp     main
3545 hidnplayr 422
 
4012 hidnplayr 423
; DNS error
3545 hidnplayr 424
fail:
425
        push    str5
426
        call    [con_write_asciiz]
4019 hidnplayr 427
        jmp     main
4012 hidnplayr 428
 
429
; Socket error
3545 hidnplayr 430
fail2:
431
        push    str6
432
        call    [con_write_asciiz]
4019 hidnplayr 433
        jmp     main
3545 hidnplayr 434
 
4019 hidnplayr 435
; Finally.. exit!
436
exit:
437
        push    1
438
        call    [con_exit]
5249 hidnplayr 439
exit_now:
4019 hidnplayr 440
        mcall   -1
441
 
442
 
5842 hidnplayr 443
ascii_to_dec:
444
 
445
        lodsb
446
        cmp     al, ' '
447
        jne     .fail
448
 
449
        xor     eax, eax
450
        xor     ebx, ebx
451
  .loop:
452
        lodsb
453
        test    al, al
454
        jz      .done
455
        cmp     al, ' '
456
        je      .done
457
        sub     al, '0'
458
        jb      .fail
459
        cmp     al, 9
460
        ja      .fail
461
        lea     ebx, [ebx*4+ebx]
462
        lea     ebx, [ebx*2+eax]
463
        jmp     .loop
464
  .fail:
465
        xor     ebx, ebx
466
  .done:
467
        dec     esi
468
        ret
469
 
470
 
471
 
472
 
3545 hidnplayr 473
; data
4019 hidnplayr 474
title   db      'ICMP echo (ping) client',0
475
str_welcome db  'Please enter the hostname or IP-address of the host you want to ping,',10
5842 hidnplayr 476
            db  'or just press enter to exit.',10,10
477
            db  'Options:',10
478
            db  ' -t            Send packets till users abort.',10
479
            db  ' -n number     Number of requests to send.',10
480
            db  ' -i TTL        Time to live.',10
481
            db  ' -l size       Size of echo request.',10
482
            db  ' -w time-out   Time-out in hundredths of a second.',10,0
4019 hidnplayr 483
str_prompt  db  10,'> ',0
4012 hidnplayr 484
str3    db      'Pinging to ',0
485
str3b   db      ' with %u data bytes',10,0
486
 
3545 hidnplayr 487
str4    db      10,0
488
str5    db      'Name resolution failed.',10,0
5842 hidnplayr 489
str6    db      'Socket error.',10,0
5249 hidnplayr 490
str13   db      'Invalid parameter(s)',10,0
4012 hidnplayr 491
 
5842 hidnplayr 492
str11   db      'Answer from %u.%u.%u.%u: ',0
493
str7    db      'bytes=%u time=%u.%u ms TTL=%u',10,0
5805 hidnplayr 494
str8    db      'Timeout',10,0
5842 hidnplayr 495
str9    db      'miscompare at offset %u.',10,0
496
str10   db      'invalid reply.',10,0
497
str14   db      'TTL expired.',10,0
3545 hidnplayr 498
 
5805 hidnplayr 499
str12   db      10,'Statistics:',10,'%u packets sent, %u packets received',10,'average response time=%u.%u ms',10,0
4012 hidnplayr 500
 
3545 hidnplayr 501
sockaddr1:
502
        dw AF_INET4
503
.port   dw 0
504
.ip     dd 0
505
        rb 10
506
 
507
time_reference  dd ?
508
ip_ptr          dd ?
509
count           dd ?
5842 hidnplayr 510
size            dd ?
511
ttl             dd ?
512
timeout         dd ?
4012 hidnplayr 513
recvd           dd ?    ; received number of bytes in last packet
3545 hidnplayr 514
 
4012 hidnplayr 515
stats:
4019 hidnplayr 516
        .tx     dd ?
517
        .rx     dd ?
518
        .time   dd ?
3545 hidnplayr 519
 
520
; import
521
align 4
522
@IMPORT:
523
 
524
library network, 'network.obj', console, 'console.obj'
525
import  network,        \
526
        getaddrinfo,    'getaddrinfo',  \
527
        freeaddrinfo,   'freeaddrinfo', \
528
        inet_ntoa,      'inet_ntoa'
529
 
530
import  console,        \
531
        con_start,      'START',        \
532
        con_init,       'con_init',     \
533
        con_write_asciiz,       'con_write_asciiz',     \
534
        con_printf,       'con_printf',     \
535
        con_exit,       'con_exit',     \
536
        con_gets,       'con_gets',\
537
        con_cls,        'con_cls',\
538
        con_getch2,     'con_getch2',\
5249 hidnplayr 539
        con_set_cursor_pos, 'con_set_cursor_pos',\
540
        con_get_flags,  'con_get_flags'
3545 hidnplayr 541
 
542
socketnum       dd ?
543
 
5842 hidnplayr 544
icmp_packet     db ICMP_ECHO    ; type
3545 hidnplayr 545
                db 0            ; code
5842 hidnplayr 546
                dw 0            ; checksum
4012 hidnplayr 547
 .id            dw IDENTIFIER   ; identifier
548
 .seq           dw 0x0000       ; sequence number
549
 .data          db 'abcdefghijklmnopqrstuvwxyz012345'
3545 hidnplayr 550
 
551
I_END:
5842 hidnplayr 552
                rb 65504-32
3545 hidnplayr 553
 
5842 hidnplayr 554
params          rb 1024
555
buffer_ptr:     rb BUFFERSIZE
3545 hidnplayr 556
 
5805 hidnplayr 557
IM_END: