Subversion Repositories Kolibri OS

Rev

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

  1. ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
  2. ;;                                                                 ;;
  3. ;; Copyright (C) KolibriOS team 2010-2020. All rights reserved.    ;;
  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.  
  17. BUFFERSIZE      = 65536
  18.  
  19. use32
  20.         org     0x0
  21.  
  22.         db      'MENUET01'      ; signature
  23.         dd      1               ; header version
  24.         dd      START           ; entry point
  25.         dd      I_END           ; initialized size
  26.         dd      IM_END+0x1000   ; required memory
  27.         dd      IM_END+0x1000   ; stack pointer
  28.         dd      params          ; parameters
  29.         dd      0               ; path
  30.  
  31. include '../../proc32.inc'
  32. include '../../macros.inc'
  33. purge mov,add,sub
  34. include '../../dll.inc'
  35. include '../../struct.inc'
  36. include '../../network.inc'
  37.  
  38. include '../icmp.inc'
  39. include '../ip.inc'
  40.  
  41.  
  42. START:
  43. ; init heap
  44.         mcall   68, 11
  45.         test    eax, eax
  46.         jz      exit
  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
  55.         push    250
  56.         push    80
  57.         push    25
  58.         push    80
  59.         call    [con_init]
  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
  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
  79. ; main loop
  80.         cmp     byte[params], 0
  81.         jne     parse_param
  82.  
  83.         push    str_welcome
  84.         call    [con_write_asciiz]
  85. main:
  86. ; write prompt
  87.         push    str_prompt
  88.         call    [con_write_asciiz]
  89. ; read string
  90.         mov     esi, params
  91.         push    1024
  92.         push    esi
  93.         call    [con_gets]
  94. ; check for exit
  95.         test    eax, eax
  96.         jz      exit
  97.         cmp     byte [esi], 10
  98.         jz      exit
  99. ; delete terminating '\n'
  100.         push    esi
  101. @@:
  102.         lodsb
  103.         test    al, al
  104.         jnz     @b
  105.         mov     [esi-2], al
  106.         pop     esi
  107.  
  108. ; reset stats
  109.         mov     [stats.tx], 0
  110.         mov     [stats.rx], 0
  111.         mov     [stats.time], 0
  112.  
  113. parse_param:
  114. ; parameters defaults
  115.         mov     [count], 4
  116.         mov     [size], 32
  117.         mov     [ttl], 128
  118.         mov     [timeout], 300
  119.  
  120. ; Check if any additional parameters were given
  121.         mov     esi, params
  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.   @@:
  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.   @@:
  184.         ; implement more parameters here
  185.   .invalid:
  186.         push    str13
  187.         call    [con_write_asciiz]
  188.         jmp     main
  189.  
  190.   .resolve:
  191. ; resolve name
  192.         push    esp     ; reserve stack place
  193.         push    esp     ; fourth parameter
  194.         push    0       ; third parameter
  195.         push    0       ; second parameter
  196.         push    params  ; first parameter
  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
  227.         cmp     eax, -1
  228.         je      fail2
  229.  
  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.  
  239.         mcall   40, EVM_STACK
  240.  
  241.         push    str3
  242.         call    [con_write_asciiz]
  243.  
  244.         push    [ip_ptr]
  245.         call    [con_write_asciiz]
  246.  
  247.         push    [size]
  248.         push    str3b
  249.         call    [con_printf]
  250.         add     esp, 2*4
  251.  
  252. mainloop:
  253.         call    [con_get_flags]
  254.         test    eax, 0x200                      ; con window closed?
  255.         jnz     exit_now
  256.  
  257.         inc     [stats.tx]
  258.         mcall   26, 10                          ; Get high precision timer count
  259.         mov     [time_reference], eax
  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
  266.  
  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.  
  274.         mcall   26, 10                          ; Get high precision timer count
  275.         sub     eax, [time_reference]
  276.         jz      @f
  277.         xor     edx, edx
  278.         mov     ebx, 100000
  279.         div     ebx
  280.         cmp     edx, 50000
  281.         jb      @f
  282.         inc     eax
  283.   @@:
  284.         mov     [time_exceeded], eax           ; Exceeded time in 1/100 s
  285.  
  286. ; Receive reply
  287.         mcall   recv, [socketnum], buffer_ptr, BUFFERSIZE, MSG_DONTWAIT
  288.         cmp     eax, -1
  289.         je      .no_response
  290.         test    eax, eax
  291.         jz      fail2
  292.  
  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
  301.         jb      .invalid
  302.         mov     [recvd], eax
  303.  
  304. ; make esi point to ICMP packet header
  305.         add     esi, buffer_ptr
  306.  
  307. ; Check identifier
  308.         mov     ax, [icmp_packet.id]
  309.         cmp     [esi + ICMP_header.Identifier], ax
  310.         jne     .receiveloop
  311.  
  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
  329.  
  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
  335.  
  336.         jmp     .invalid
  337.  
  338.  
  339.   .echo_reply:
  340.  
  341. ; Validate the payload
  342.         add     esi, sizeof.ICMP_header
  343.         mov     ecx, [size]
  344.         mov     edi, icmp_packet.data
  345.         repe    cmpsb
  346.         jne     .miscomp
  347.  
  348. ; update stats
  349.         inc     [stats.rx]
  350.         mov     eax, [time_exceeded]
  351.         add     [stats.time], eax
  352.  
  353. ; Print time exceeded
  354.         movzx   eax, [buffer_ptr + IPv4_header.TimeToLive]
  355.         push    eax
  356.         mov     eax, [time_exceeded]
  357.         xor     edx, edx
  358.         mov     ebx, 10
  359.         div     ebx
  360.         push    edx
  361.         push    eax
  362.         push    [recvd]
  363.  
  364.         push    str7
  365.         call    [con_printf]
  366.         add     esp, 5*4
  367.  
  368.         jmp     .continue
  369.  
  370.  
  371.   .ttl_exceeded:
  372.         push    str14
  373.         call    [con_write_asciiz]
  374.  
  375.         jmp     .continue
  376.  
  377.  
  378. ; Error in packet, print it to user
  379.   .miscomp:
  380.         sub     edi, icmp_packet.data+1
  381.         push    edi
  382.         push    str9
  383.         call    [con_printf]
  384.         add     esp, 2*4
  385.         jmp     .continue
  386.  
  387. ; Invalid reply
  388.   .invalid:
  389.         push    str10
  390.         call    [con_write_asciiz]
  391.         jmp     .continue
  392.  
  393. ; Timeout!
  394.   .no_response:
  395.         push    str8
  396.         call    [con_write_asciiz]
  397.  
  398. ; Send more ICMP packets ?
  399.   .continue:
  400.         inc     [icmp_packet.seq]
  401.  
  402.         cmp     [count], -1
  403.         je      .forever
  404.         dec     [count]
  405.         jz      .stats
  406.   .forever:
  407. ; wait a second before sending next request
  408.         mcall   5, 100
  409.         jmp     mainloop
  410.  
  411. ; Print statistics
  412.   .stats:
  413.         cmp     [stats.rx], 0
  414.         jne     @f
  415.         xor     eax, eax
  416.         xor     edx, edx
  417.         jmp     .zero
  418.   @@:
  419.         xor     edx, edx
  420.         mov     eax, [stats.time]
  421.         div     [stats.rx]
  422.         xor     edx, edx
  423.         mov     ebx, 10
  424.         div     ebx
  425.   .zero:
  426.         push    edx
  427.         push    eax
  428.         push    [stats.rx]
  429.         push    [stats.tx]
  430.         push    str12
  431.         call    [con_printf]
  432.         add     esp, 5*4
  433.         jmp     main
  434.  
  435. ; DNS error
  436. fail:
  437.         push    str5
  438.         call    [con_write_asciiz]
  439.         jmp     main
  440.  
  441. ; Socket error
  442. fail2:
  443.         push    str6
  444.         call    [con_write_asciiz]
  445.         jmp     main
  446.  
  447. ; Finally.. exit!
  448. exit:
  449.         push    1
  450.         call    [con_exit]
  451. exit_now:
  452.         mcall   -1
  453.  
  454.  
  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.  
  485. ; data
  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
  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
  495. str_prompt  db  10,'> ',0
  496. str3    db      'Pinging to ',0
  497. str3b   db      ' with %u data bytes',10,0
  498.  
  499. str4    db      10,0
  500. str5    db      'Name resolution failed.',10,0
  501. str6    db      'Socket error.',10,0
  502. str13   db      'Invalid parameter(s)',10,0
  503.  
  504. str11   db      'Answer from %u.%u.%u.%u: ',0
  505. str7    db      'bytes=%u time=%u.%u ms TTL=%u',10,0
  506. str8    db      'Timeout',10,0
  507. str9    db      'miscompare at offset %u.',10,0
  508. str10   db      'invalid reply.',10,0
  509. str14   db      'TTL expired.',10,0
  510.  
  511. str12   db      10,'Statistics:',10,'%u packets sent, %u packets received',10,'average response time=%u.%u ms',10,0
  512.  
  513. sockaddr1:
  514.         dw AF_INET4
  515. .port   dw 0
  516. .ip     dd 0
  517.         rb 10
  518.  
  519. time_reference  dd ?    ; start time of sent packet
  520. time_exceeded   dd ?    ; time exceeded between send and receive
  521. ip_ptr          dd ?
  522. count           dd ?
  523. size            dd ?
  524. ttl             dd ?
  525. timeout         dd ?
  526. recvd           dd ?    ; received number of bytes in last packet
  527.  
  528. stats:
  529.         .tx     dd ?
  530.         .rx     dd ?
  531.         .time   dd ?
  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',\
  552.         con_set_cursor_pos, 'con_set_cursor_pos',\
  553.         con_get_flags,  'con_get_flags'
  554.  
  555. socketnum       dd ?
  556.  
  557. icmp_packet     db ICMP_ECHO    ; type
  558.                 db 0            ; code
  559.                 dw 0            ; checksum
  560.  .id            dw 0            ; identifier
  561.  .seq           dw 0x0000       ; sequence number
  562.  .data          db 'abcdefghijklmnopqrstuvwxyz012345'
  563.  
  564. I_END:
  565.                 rb 65504-32
  566.  
  567. thread_info process_information
  568.  
  569. params          rb 1024
  570. buffer_ptr:     rb BUFFERSIZE
  571.  
  572. IM_END:
  573.