Subversion Repositories Kolibri OS

Rev

Go to most recent revision | Details | Last modification | View Log | RSS feed

Rev Author Line No. Line
485 heavyiron 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