Subversion Repositories Kolibri OS

Rev

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

  1. ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
  2. ;;                                                                 ;;
  3. ;; Copyright (C) KolibriOS team 2010-2015. 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      = 1500
  18. IDENTIFIER      = 0x1337
  19.  
  20. use32
  21.         org     0x0
  22.  
  23.         db      'MENUET01'      ; signature
  24.         dd      1               ; header version
  25.         dd      START           ; entry point
  26.         dd      I_END           ; initialized size
  27.         dd      IM_END+0x1000   ; required memory
  28.         dd      IM_END+0x1000   ; stack pointer
  29.         dd      params          ; parameters
  30.         dd      0               ; path
  31.  
  32. include '../../proc32.inc'
  33. include '../../macros.inc'
  34. purge mov,add,sub
  35. include '../../dll.inc'
  36. include '../../struct.inc'
  37. include '../../network.inc'
  38.  
  39. include '../icmp.inc'
  40. include '../ip.inc'
  41.  
  42.  
  43. START:
  44. ; init heap
  45.         mcall   68, 11
  46.         test    eax, eax
  47.         jz      exit
  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
  56.         push    250
  57.         push    80
  58.         push    25
  59.         push    80
  60.         call    [con_init]
  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
  76. ; main loop
  77.         cmp     byte[params], 0
  78.         jne     parse_param
  79.  
  80.         push    str_welcome
  81.         call    [con_write_asciiz]
  82. main:
  83. ; write prompt
  84.         push    str_prompt
  85.         call    [con_write_asciiz]
  86. ; read string
  87.         mov     esi, params
  88.         push    1024
  89.         push    esi
  90.         call    [con_gets]
  91. ; check for exit
  92.         test    eax, eax
  93.         jz      exit
  94.         cmp     byte [esi], 10
  95.         jz      exit
  96. ; delete terminating '\n'
  97.         push    esi
  98. @@:
  99.         lodsb
  100.         test    al, al
  101.         jnz     @b
  102.         mov     [esi-2], al
  103.         pop     esi
  104.  
  105. ; reset stats
  106.         mov     [stats.tx], 0
  107.         mov     [stats.rx], 0
  108.         mov     [stats.time], 0
  109.  
  110. parse_param:
  111. ; parameters defaults
  112.         mov     [count], 4
  113.         mov     [size], 32
  114.         mov     [ttl], 128
  115.         mov     [timeout], 300
  116.  
  117. ; Check if any additional parameters were given
  118.         mov     esi, params
  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.   @@:
  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.   @@:
  181.         ; implement more parameters here
  182.   .invalid:
  183.         push    str13
  184.         call    [con_write_asciiz]
  185.         jmp     main
  186.  
  187.   .resolve:
  188. ; resolve name
  189.         push    esp     ; reserve stack place
  190.         push    esp     ; fourth parameter
  191.         push    0       ; third parameter
  192.         push    0       ; second parameter
  193.         push    params  ; first parameter
  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
  224.         cmp     eax, -1
  225.         je      fail2
  226.  
  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.  
  236.         mcall   40, EVM_STACK
  237.  
  238.         push    str3
  239.         call    [con_write_asciiz]
  240.  
  241.         push    [ip_ptr]
  242.         call    [con_write_asciiz]
  243.  
  244.         push    [size]
  245.         push    str3b
  246.         call    [con_printf]
  247.         add     esp, 2*4
  248.  
  249. mainloop:
  250.         call    [con_get_flags]
  251.         test    eax, 0x200                      ; con window closed?
  252.         jnz     exit_now
  253.  
  254.         inc     [stats.tx]
  255.         mcall   26, 10                          ; Get high precision timer count
  256.         mov     [time_reference], eax
  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
  263.  
  264.         mcall   23, [timeout]
  265.         mcall   26, 10                          ; Get high precision timer count
  266.         sub     eax, [time_reference]
  267.         jz      @f
  268.         xor     edx, edx
  269.         mov     ebx, 100000
  270.         div     ebx
  271.         cmp     edx, 50000
  272.         jb      @f
  273.         inc     eax
  274.   @@:
  275.         mov     [time_reference], eax
  276.  
  277. ; Receive reply
  278.         mcall   recv, [socketnum], buffer_ptr, BUFFERSIZE, MSG_DONTWAIT
  279.         cmp     eax, -1
  280.         je      .no_response
  281.         test    eax, eax
  282.         jz      fail2
  283.  
  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
  292.         jb      .invalid
  293.         mov     [recvd], eax
  294.  
  295. ; make esi point to ICMP packet header
  296.         add     esi, buffer_ptr
  297.  
  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
  315.  
  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
  321.  
  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]
  333.         mov     edi, icmp_packet.data
  334.         repe    cmpsb
  335.         jne     .miscomp
  336.  
  337. ; update stats
  338.         inc     [stats.rx]
  339.         mov     eax, [time_reference]
  340.         add     [stats.time], eax
  341.  
  342.         movzx   eax, [buffer_ptr + IPv4_header.TimeToLive]
  343.         push    eax
  344.         mov     eax, [time_reference]
  345.         xor     edx, edx
  346.         mov     ebx, 10
  347.         div     ebx
  348.         push    edx
  349.         push    eax
  350.         push    [recvd]
  351.  
  352.         push    str7
  353.         call    [con_printf]
  354.         add     esp, 5*4
  355.  
  356.         jmp     .continue
  357.  
  358.  
  359.   .ttl_exceeded:
  360.         push    str14
  361.         call    [con_write_asciiz]
  362.  
  363.         jmp     .continue
  364.  
  365.  
  366. ; Error in packet, print it to user
  367.   .miscomp:
  368.         sub     edi, icmp_packet.data+1
  369.         push    edi
  370.         push    str9
  371.         call    [con_printf]
  372.         add     esp, 2*4
  373.         jmp     .continue
  374.  
  375. ; Invalid reply
  376.   .invalid:
  377.         push    str10
  378.         call    [con_write_asciiz]
  379.         jmp     .continue
  380.  
  381. ; Timeout!
  382.   .no_response:
  383.         push    str8
  384.         call    [con_write_asciiz]
  385.  
  386. ; Send more ICMP packets ?
  387.   .continue:
  388.         inc     [icmp_packet.seq]
  389.  
  390.         cmp     [count], -1
  391.         je      .forever
  392.         dec     [count]
  393.         jz      .stats
  394.   .forever:
  395. ; wait a second before sending next request
  396.         mcall   5, 100
  397.         jmp     mainloop
  398.  
  399. ; Print statistics
  400.   .stats:
  401.         cmp     [stats.rx], 0
  402.         jne     @f
  403.         xor     eax, eax
  404.         xor     edx, edx
  405.         jmp     .zero
  406.   @@:
  407.         xor     edx, edx
  408.         mov     eax, [stats.time]
  409.         div     [stats.rx]
  410.         xor     edx, edx
  411.         mov     ebx, 10
  412.         div     ebx
  413.   .zero:
  414.         push    edx
  415.         push    eax
  416.         push    [stats.rx]
  417.         push    [stats.tx]
  418.         push    str12
  419.         call    [con_printf]
  420.         add     esp, 5*4
  421.         jmp     main
  422.  
  423. ; DNS error
  424. fail:
  425.         push    str5
  426.         call    [con_write_asciiz]
  427.         jmp     main
  428.  
  429. ; Socket error
  430. fail2:
  431.         push    str6
  432.         call    [con_write_asciiz]
  433.         jmp     main
  434.  
  435. ; Finally.. exit!
  436. exit:
  437.         push    1
  438.         call    [con_exit]
  439. exit_now:
  440.         mcall   -1
  441.  
  442.  
  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.  
  473. ; data
  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
  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
  483. str_prompt  db  10,'> ',0
  484. str3    db      'Pinging to ',0
  485. str3b   db      ' with %u data bytes',10,0
  486.  
  487. str4    db      10,0
  488. str5    db      'Name resolution failed.',10,0
  489. str6    db      'Socket error.',10,0
  490. str13   db      'Invalid parameter(s)',10,0
  491.  
  492. str11   db      'Answer from %u.%u.%u.%u: ',0
  493. str7    db      'bytes=%u time=%u.%u ms TTL=%u',10,0
  494. str8    db      'Timeout',10,0
  495. str9    db      'miscompare at offset %u.',10,0
  496. str10   db      'invalid reply.',10,0
  497. str14   db      'TTL expired.',10,0
  498.  
  499. str12   db      10,'Statistics:',10,'%u packets sent, %u packets received',10,'average response time=%u.%u ms',10,0
  500.  
  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 ?
  510. size            dd ?
  511. ttl             dd ?
  512. timeout         dd ?
  513. recvd           dd ?    ; received number of bytes in last packet
  514.  
  515. stats:
  516.         .tx     dd ?
  517.         .rx     dd ?
  518.         .time   dd ?
  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',\
  539.         con_set_cursor_pos, 'con_set_cursor_pos',\
  540.         con_get_flags,  'con_get_flags'
  541.  
  542. socketnum       dd ?
  543.  
  544. icmp_packet     db ICMP_ECHO    ; type
  545.                 db 0            ; code
  546.                 dw 0            ; checksum
  547.  .id            dw IDENTIFIER   ; identifier
  548.  .seq           dw 0x0000       ; sequence number
  549.  .data          db 'abcdefghijklmnopqrstuvwxyz012345'
  550.  
  551. I_END:
  552.                 rb 65504-32
  553.  
  554. params          rb 1024
  555. buffer_ptr:     rb BUFFERSIZE
  556.  
  557. IM_END:
  558.