Subversion Repositories Kolibri OS

Rev

Rev 260 | Blame | Last modification | View Log | Download | RSS feed

  1. ;
  2. ; ETH.INC
  3. ;
  4. ; made by hidnplayr (hidnplayr@gmail.com) for KolibriOS
  5. ;
  6. ; The given code before every macro is only a simple example
  7. ;
  8. ;
  9. ; HISTORY
  10. ;
  11. ; v1.0: 18 august 2006  original release
  12. ; v1.1: december 2006   bugfixes and improvements
  13. ;
  14.  
  15. macro mov arg1,arg2 {
  16.     if arg1 eq arg2
  17.     else
  18.     mov arg1,arg2
  19.     end if
  20. }
  21.  
  22. TCB_LISTEN = 1
  23. TCB_SYN_SENT = 2
  24. TCB_SYN_RECEIVED = 3
  25. TCB_ESTABLISHED = 4
  26. TCB_FIN_WAIT_1 = 5
  27. TCB_FIN_WAIT_2 = 6
  28. TCB_CLOSE_WAIT = 7
  29. TCB_CLOSING = 8
  30. TCB_LAST_ASK = 9
  31. TCB_TIME_WAIT = 10
  32. TCB_CLOSED = 11
  33.  
  34. PASSIVE = 0
  35. ACTIVE = 1
  36.  
  37. ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
  38.  
  39. ;   eth.get_IP eax
  40. ;
  41. ;   gets the current IP that is defined in Stack (return in eax in this example)
  42. macro eth.get_IP IP {
  43.     mov  ebx,1
  44.     mov  eax,52
  45.     mcall
  46.  
  47.     mov  IP ,eax
  48. }
  49.  
  50. ;   eth.get_GATEWAY eax
  51. ;
  52. ;   gets the current GATEWAY that is defined in Stack (return in eax in this example)
  53. macro eth.get_GATEWAY GATEWAY {
  54.     mov  ebx,9
  55.     mov  eax,52
  56.     mcall
  57.     move GATEWAY ,eax
  58. }
  59.  
  60. ;   eth.get_SUBNET eax
  61. ;
  62. ;   gets the current SUBNET that is defined in Stack (return in eax in this example)
  63. macro eth.get_SUBNET SUBNET {
  64.     mov  ebx,10
  65.     mov  eax,52
  66.     mcall
  67.     mov SUBNET ,eax
  68. }
  69.  
  70. ;   eth.get_DNS eax
  71. ;
  72. ;   gets the current DNS that is defined in Stack (return in eax in this example)
  73. macro eth.get_DNS DNS {
  74.     mov  ebx,13
  75.     mov  eax,52
  76.     mcall
  77.     mov  DNS ,eax
  78. }
  79.  
  80. ;   eth.set_IP eax
  81. ;
  82. ;   set a new IP in stack (input in eax in this example)
  83. macro eth.set_IP IP {
  84.     mov  ecx,IP
  85.     mov  ebx,3
  86.     mov  eax,52
  87.     mcall
  88. }
  89.  
  90. ;   eth.set_GATEWAY eax
  91. ;
  92. ;   set a new GATEWAY in stack (input in eax in this example)
  93. macro eth.set_GATEWAY GATEWAY {
  94.     mov  ecx,GATEWAY
  95.     mov  ebx,11
  96.     mov  eax,52
  97.     mcall
  98. }
  99.  
  100. ;   eth.set_SUBNET eax
  101. ;
  102. ;   set a new SUBNET in stack (input in eax in this example)
  103. macro eth.set_SUBNET SUBNET {
  104.     mov  ecx,SUBNET
  105.     mov  ebx,12
  106.     mov  eax,52
  107.     mcall
  108. }
  109.  
  110. ;   eth.set_DNS eax
  111. ;
  112. ;   set a new DNS in stack (input in eax in this example)
  113. macro eth.set_DNS DNS {
  114.     mov  ecx,DNS
  115.     mov  ebx,14
  116.     mov  eax,52
  117.     mcall
  118. }
  119.  
  120. ;   eth.open eax,80,ebx,[socket]
  121. ;
  122. ;   open a socket on local port in eax to port 80 on server on ebx
  123. ;   the socketnumber will be returned in [socket] (dword)
  124. macro eth.open_udp local,remote,ip,socket {
  125.     mov  ecx, local
  126.     mov  edx, remote
  127.     mov  esi, ip
  128.     mov  ebx, 0
  129.     mov  eax, 53
  130.     mcall
  131.  
  132.     mov  socket,eax
  133. }
  134.  
  135. ;   eth.close [socket]
  136. ;
  137. ;   closes socket on socketnumber [socket]
  138. macro eth.close_udp socket {
  139.     mov  ecx, socket
  140.     mov  ebx, 1
  141.     mov  eax, 53
  142.     mcall
  143. }
  144.  
  145. ;   eth.poll [socket],eax
  146. ;
  147. ;   polls [socket] for data
  148. ;   eax = 0 when there is data
  149. macro eth.poll socket {
  150.     mov  ecx, socket
  151.     mov  ebx, 2
  152.     mov  eax, 53
  153.     mcall
  154. }
  155.  
  156. ;   eth.read_byte [socket], bl
  157. ;
  158. ;   reads a byte from the socket and returns in bl
  159. macro eth.read_byte socket, result {
  160.     mov  ecx, socket
  161.     mov  ebx, 3
  162.     mov  eax, 53
  163.     mcall
  164.  
  165.     mov  result,bl
  166. }
  167.  
  168. ;   eth.read_byte [socket], bl
  169. ;
  170. ;   reads a byte from the socket and returns in bl
  171. macro eth.read_packet socket, result {
  172.     mov  edx, result
  173.     mov  ecx, socket
  174.     mov  ebx, 10
  175.     mov  eax, 53
  176.     mcall
  177. }
  178.  
  179. ;   eth.write [socket],12,msg
  180. ;   msg db 'hello world!'
  181. ;
  182. ;   send message msg to socket
  183. macro eth.write_udp socket,length,msg,verify {
  184.     mov  ecx, socket
  185.     mov  edx, length
  186.     mov  esi, msg
  187.     mov  ebx, 4
  188.     mov  eax, 53
  189.     mcall
  190.  
  191.     if verify eq 1
  192.     call verifysend
  193.     end if
  194.  
  195. }
  196.  
  197. verifysend:
  198.     test eax,eax
  199.     jnz  @f
  200.     ret
  201. @@:
  202.     pusha
  203.     mov  eax,5
  204.     mov  ebx,100
  205.     mcall
  206.  
  207.     popa
  208.     mcall
  209. ret
  210.  
  211. ;   eth.open_tcp 80,80,eax,0,[socket]
  212. ;
  213. ;   opens a tcp socket on port 80 to port 80 on IP eax with passive open
  214. ;   returns socket number in eax
  215. macro eth.open_tcp local,remote,ip,passive,socket {
  216.  
  217.     mov  ecx, local
  218.     mov  edx, remote
  219.     mov  esi, ip
  220.     mov  edi, passive      ; 0 = PASSIVE open
  221.     mov  ebx, 5
  222.     mov  eax, 53
  223.     mcall
  224.  
  225.     mov  socket,eax
  226. }
  227.  
  228. ;   eth.socket_status [socket],eax
  229. ;
  230. ;   returns socket status in eax
  231. macro eth.socket_status socket,result {
  232.     mov  ecx, socket
  233.     mov  ebx, 6
  234.     mov  eax, 53
  235.     mcall
  236.  
  237.     mov  result,eax
  238. }
  239.  
  240. ;   eth.write_tcp [socket],12,msg
  241. ;
  242. ;   msg db 'hello world!'
  243. ;
  244. ;   send message to TCP socket
  245. macro eth.write_tcp socket,length,msg,verify {
  246.     mov  ecx, socket
  247.     mov  edx, length
  248.     mov  esi, msg
  249.     mov  ebx, 7
  250.     mov  eax, 53
  251.     mcall
  252.  
  253.     if verify eq 1
  254.     call verifysend
  255.     end if
  256. }
  257.  
  258. ;   eth.close_tcp [socket]
  259. ;
  260. ;   closes tcp socket [socket]
  261. macro eth.close_tcp socket {
  262.     mov  ecx, socket
  263.     mov  ebx, 8
  264.     mov  eax, 53
  265.     mcall
  266. }
  267.  
  268. ;   eth.check_port 165,eax
  269. ;
  270. ;   checks if port 165 is used
  271. ;   return is 0 when port is free
  272. macro eth.check_port port,result {
  273.     mov  ecx, port
  274.     mov  ebx, 9
  275.     mov  eax, 53
  276.     mcall
  277.  
  278.     mov  result,eax
  279. }
  280.  
  281. ;   eth.status eax
  282. ;
  283. ;   returns socket status in eax
  284. macro eth.status status {
  285.     mov  ebx, 255
  286.     mov  ecx, 6
  287.     mov  eax, 53
  288.     mcall
  289.  
  290.     mov  status,eax
  291. }
  292.  
  293. ;   eth.search 165,edx
  294. ;
  295. ;   searches a free local port starting from 166 (165 + 1 !)
  296. ;   returns in edx
  297. macro eth.search_port port,result {
  298.     mov  edx,port
  299.    @@:
  300.     inc  edx
  301.     eth.check_port edx,eax
  302.     cmp  eax,0
  303.     je   @r
  304.     mov  result,edx
  305. }
  306.  
  307.  
  308.  
  309. ;   eth.read_data [socket],buffer,512
  310. ;   buffer  rb 512
  311. ;   socket  dd ?
  312. ;
  313. ;   reads data from socket into a buffer, stops when there is no more data or buffer is full.
  314. macro eth.read_data socket,dest,endptr,bufferl {
  315. local .getdata,.loop,.end
  316.     mov     eax, dest
  317.     mov     endptr, eax
  318.  
  319.     ; we have data - this will be the response
  320. .getdata:
  321.     mov     eax,endptr
  322.     cmp     eax,bufferl
  323.     jg      .end
  324.  
  325.     eth.read_byte socket,bl
  326.  
  327.     ; Store the data in the response buffer
  328.     mov     eax, endptr
  329.     mov     [eax], bl
  330.     inc     dword endptr
  331.  
  332.     eth.poll socket
  333.  
  334.     cmp     eax,0
  335.     jne     .getdata                  ; yes, so get it
  336.  
  337.     ; now we are going to wait 30 times 10 ms (300ms)
  338.  
  339.     mov     edx,0
  340. .loop:
  341.     mov     eax,5
  342.     mov     ebx,1
  343.     mcall
  344.  
  345.     eth.poll socket
  346.  
  347.     cmp     eax, 0
  348.     jne     .getdata                  ; yes, so get it
  349.  
  350.     inc     edx
  351.     cmp     edx,100
  352.     jl      .loop
  353.  
  354. .end:
  355.  
  356. }
  357.  
  358. ;  eth.wait_for_data [socket],60,abort
  359. ;  eth.read_data ....
  360. ;  abort:
  361. ;
  362. ;  Waits for data with timeout
  363.  
  364. macro eth.wait_for_data socket,TIMEOUT,abort {
  365.  
  366.     mov   edx,TIMEOUT
  367.  
  368.    @@:
  369.     eth.poll socket
  370.  
  371.     cmp   eax,0
  372.     jne   @f
  373.  
  374.     dec   edx
  375.     jz    abort
  376.  
  377.     mov   eax,5                               ; wait here for event
  378.     mov   ebx,10
  379.     mcall
  380.  
  381.     jmp   @r
  382.    @@:
  383.  
  384. }
  385.  
  386.  
  387. ; The function 'resolve' resolves the address in edx and puts the resulting IP in eax.
  388. ; When the input is an IP-adress, the function will output this IP in eax.
  389. ; If something goes wrong, the result in eax should be 0
  390. ;
  391. ; example:
  392. ;
  393. ; resolve query1,IP,PORT
  394. ; resolve '192.168.0.1',IP,PORT
  395. ; resolve query2,IP,PORT
  396. ;
  397. ; query1 db 'www.google.com',0
  398. ; query2 db '49.78.84.45',0
  399. ; IP     dd ?
  400. ; PORT   dd ?
  401.  
  402. macro resolve query,result {
  403.  
  404. if    query eqtype 0
  405.  mov   edx,query
  406. else
  407.  local ..string, ..label
  408.  jmp   ..label
  409.  ..string db query,0
  410.  ..label:
  411.  mov   edx,..string
  412. end   if
  413.  
  414. call  __resolve
  415.  
  416. mov   result,eax
  417.  
  418. }
  419.  
  420. if used __resolve
  421.  
  422. __resolve:
  423.  
  424. if __DEBUG__ eq 1
  425. DEBUGF 1,'Resolving started\n'
  426. end if
  427.  
  428.     ; This code validates if the query is an IP containing 4 numbers and 3 dots
  429.  
  430.  
  431.     push    edx               ; push edx (query address) onto stack
  432.     xor     al, al            ; make al (dot count) zero
  433.  
  434.    @@:
  435.     cmp     byte[edx],'0'     ; check if this byte is a number, if not jump to no_IP
  436.     jl      no_IP             ;
  437.     cmp     byte[edx],'9'     ;
  438.     jg      no_IP             ;
  439.  
  440.     inc     edx               ; the byte was a number, so lets check the next byte
  441.  
  442.     cmp     byte[edx],0       ; is this byte zero? (have we reached end of query?)
  443.     jz      @f                ; jump to next @@ then
  444.     cmp     byte[edx],':'
  445.     jz      @f
  446.  
  447.     cmp     byte[edx],'.'     ; is this byte a dot?
  448.     jne     @r                ; if not, jump to previous @@
  449.  
  450.     inc     al                ; the byte was a dot so increment al(dot count)
  451.     inc     edx               ; next byte
  452.     jmp     @r                ; lets check for numbers again (jump to previous @@)
  453.  
  454.    @@:                        ; we reach this when end of query reached
  455.     cmp     al,3              ; check if there where 3 dots
  456.     jnz     no_IP             ; if not, jump to no_IP (this is where the DNS will take over)
  457.  
  458.     ; The following code will convert this IP into a dword and output it in eax
  459.     ; If there is also a port number specified, this will be returned in ebx, otherwise ebx is -1
  460.  
  461.     pop     esi               ; edx (query address) was pushed onto stack and is now popped in esi
  462.  
  463.     xor     edx, edx          ; result
  464.     xor     eax, eax          ; current character
  465.     xor     ebx, ebx          ; current byte
  466.  
  467. .outer_loop:
  468.     shl     edx, 8
  469.     add     edx, ebx
  470.     xor     ebx, ebx
  471. .inner_loop:
  472.     lodsb
  473.     test    eax, eax
  474.     jz      .finish
  475.     cmp     al, '.'
  476.     jz      .outer_loop
  477.     sub     eax, '0'
  478.     imul    ebx, 10
  479.     add     ebx, eax
  480.     jmp     .inner_loop
  481. .finish:
  482.     shl     edx, 8
  483.     add     edx, ebx
  484.  
  485.     bswap   edx               ; we want little endian order
  486.     mov     eax, edx
  487.  
  488.     ret
  489.  
  490.  
  491. no_IP:
  492.  
  493.     pop     edx
  494.  
  495.     ; The query is not an IP address, we will send the query to a DNS server and hope for answer ;)
  496. if __DEBUG__ eq 1
  497.     DEBUGF 1,'The query is no ip, Building request string from:%u\n',edx
  498. end if
  499.  
  500.     ; Build the request string
  501.     mov     eax, 0x00010100
  502.     mov     [dnsMsg], eax
  503.     mov     eax, 0x00000100
  504.     mov     [dnsMsg+4], eax
  505.     mov     eax, 0x00000000
  506.     mov     [dnsMsg+8], eax
  507.  
  508.     ; domain name goes in at dnsMsg+12
  509.     mov     esi, dnsMsg + 12                     ; location of label length
  510.     mov     edi, dnsMsg + 13                     ; label start
  511.     mov     ecx, 12                              ; total string length so far
  512.  
  513. td002:
  514.     mov     [esi], byte 0
  515.     inc     ecx
  516.  
  517. td0021:
  518.     mov     al, [edx]
  519.  
  520.     cmp     al, 0
  521.     je      td001                                ; we have finished the string translation
  522.  
  523.     cmp     al, '.'
  524.     je      td004                                ; we have finished the label
  525.  
  526.     inc     byte [esi]
  527.     inc     ecx
  528.     mov     [edi], al
  529.     inc     edi
  530.     inc     edx
  531.     jmp     td0021
  532.  
  533. td004:
  534.     mov     esi, edi
  535.     inc     edi
  536.     inc     edx
  537.     jmp     td002
  538.  
  539.     ; write label len + label text
  540. td001:
  541.     mov     [edi], byte 0
  542.     inc     ecx
  543.     inc     edi
  544.     mov     [edi], dword 0x01000100
  545.     add     ecx, 4
  546.  
  547.     mov     [dnsMsgLen], ecx                     ; We'll need the length of the message when we send it
  548.     ; Now, lets send this and wait for an answer
  549.  
  550.     eth.search_port 1024,edx                     ; Find a free port starting from 1025 and store in edx
  551.     eth.get_DNS esi                              ; Read DNS IP from stack into esi
  552.     eth.open_udp edx,53,esi,[socketNum]              ; First, open socket
  553. if __DEBUG__ eq 1
  554.     DEBUGF 1,'Socket opened: %u (port %u)\n',[socketNum],ecx
  555. end if
  556.     eth.write_udp [socketNum],[dnsMsgLen],dnsMsg     ; Write to socket ( request DNS lookup )
  557. if __DEBUG__ eq 1
  558.     DEBUGF 1,'Data written, length:%u offset:%u\n',[dnsMsgLen],dnsMsg
  559.     DEBUGF 1,'Waiting for data: (timeout is %us)\n',TIMEOUT
  560. end if
  561.     eth.wait_for_data [socketNum],TIMEOUT,abort  ; Now, we wait for data from remote
  562.     eth.read_data [socketNum],dnsMsg,[dnsMsgLen],dnsMsg+BUFFER      ; Read the data into the buffer
  563. if __DEBUG__ eq 1
  564.     DEBUGF 1,'Data received, offset:%u buffer size:%u length:%u\n',dnsMsg,BUFFER,esi-dnsMsg
  565. end if
  566.     eth.close_udp [socketNum]                        ; We're done, close the socket
  567. if __DEBUG__ eq 1
  568.     DEBUGF 1,'Closed Socket\n'
  569. end if
  570.  
  571.     ; Now parse the message to get the host IP. Man, this is complicated. It's described in RFC 1035
  572.     ; 1) Validate that we have an answer with > 0 responses
  573.     ; 2) Find the answer record with TYPE 0001 ( host IP )
  574.     ; 3) Finally, copy the IP address to the display
  575.     ; Note: The response is in dnsMsg, the end of the buffer is pointed to by [dnsMsgLen]
  576.  
  577.     mov     esi, dnsMsg
  578.  
  579.     mov     al, [esi+2]                          ; Is this a response to my question?
  580.     and     al, 0x80
  581.     cmp     al, 0x80
  582.     jne     abort
  583. if __DEBUG__ eq 1
  584.     DEBUGF 1,'It was a response to my question\n'
  585. end if
  586.  
  587.     mov     al, [esi+3]                          ; Were there any errors?
  588.     and     al, 0x0F
  589.     cmp     al, 0x00
  590.     jne     abort
  591.  
  592. if __DEBUG__ eq 1
  593.     DEBUGF 1,'There were no errors\n'
  594. end if
  595.  
  596.     mov     ax, [esi+6]                          ; Is there ( at least 1 ) answer?
  597.     cmp     ax, 0x00
  598.     je      abort
  599.  
  600.     ; Header validated. Scan through and get my answer
  601.     add     esi, 12                              ; Skip to the question field
  602.     call    skipName                             ; Skip through the question field
  603.     add     esi, 4                               ; skip past the questions qtype, qclass
  604.  
  605. ctr002z:
  606.     ; Now at the answer. There may be several answers, find the right one ( TYPE = 0x0001 )
  607.     call    skipName
  608.     mov     ax, [esi]
  609.     cmp     ax, 0x0100                           ; Is this the IP address answer?
  610.     jne     ctr002c
  611.     add     esi, 10                              ; Yes! Point eax to the first byte of the IP address
  612.     mov     eax,[esi]
  613.  
  614.     ret
  615.  
  616.  
  617. ctr002c:                                         ; Skip through the answer, move to the next
  618.     add     esi, 8
  619.     movzx   eax, byte [esi+1]
  620.     mov     ah, [esi]
  621.     add     esi, eax
  622.     add     esi, 2
  623.  
  624.     cmp     esi, [dnsMsgLen]                     ; Have we reached the end of the msg? This is an error condition, should not happen
  625.     jl      ctr002z                              ; Check next answer
  626.  
  627. abort:
  628. if __DEBUG__ eq 1
  629.     DEBUGF 1,'Something went wrong, aborting\n'
  630. end if
  631.     xor     eax,eax
  632.  
  633.     ret
  634.  
  635.  
  636. skipName:
  637.     ; Increment esi to the first byte past the name field
  638.     ; Names may use compressed labels. Normally do.
  639.     ; RFC 1035 page 30 gives details
  640.     mov     al, [esi]
  641.     cmp     al, 0
  642.     je      sn_exit
  643.     and     al, 0xc0
  644.     cmp     al, 0xc0
  645.     je      sn001
  646.  
  647.     movzx   eax, byte [esi]
  648.     inc     eax
  649.     add     esi, eax
  650.     jmp     skipName
  651.  
  652. sn001:
  653.     add     esi, 2                               ; A pointer is always at the end
  654.     ret
  655.  
  656. sn_exit:
  657.     inc     esi
  658.     ret
  659.  
  660. dnsMsgLen:      dd 0
  661. socketNum:      dd 0xFFFF
  662.  
  663. if ~defined dnsMsg
  664. dnsMsg:         rb BUFFER
  665. end if
  666.  
  667. end if
  668.  
  669.  
  670.  
  671.  
  672.