Subversion Repositories Kolibri OS

Rev

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

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