Subversion Repositories Kolibri OS

Rev

Rev 7891 | Blame | Compare with Previous | Last modification | View Log | Download | RSS feed

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