Subversion Repositories Kolibri OS

Rev

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

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