Subversion Repositories Kolibri OS

Rev

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

Rev Author Line No. Line
1155 clevermous 1
format MS COFF
2
 
3
public @EXPORT as 'EXPORTS'
4
 
5
include '../../../struct.inc'
6
include '../../../proc32.inc'
7
include '../../../macros.inc'
8
purge section,mov,add,sub
9
 
10
include 'network.inc'
11
 
12
section '.flat' code readable align 16
13
 
14
;;===========================================================================;;
15
lib_init: ;//////////////////////////////////////////////////////////////////;;
16
;;---------------------------------------------------------------------------;;
17
;? Library entry point (called after library load)                           ;;
18
;;---------------------------------------------------------------------------;;
19
;> eax = pointer to memory allocation routine                                ;;
20
;> ebx = pointer to memory freeing routine                                   ;;
21
;> ecx = pointer to memory reallocation routine                              ;;
22
;> edx = pointer to library loading routine                                  ;;
23
;;---------------------------------------------------------------------------;;
24
;< eax = 1 (fail) / 0 (ok) (library initialization result)                   ;;
25
;;===========================================================================;;
26
	mov	[mem.alloc], eax
27
	mov	[mem.free], ebx
28
	mov	[mem.realloc], ecx
29
	mov	[dll.load], edx
30
	mov	[DNSrequestID], 1
31
	stdcall	edx, @IMPORT
32
	ret	4
33
 
34
;;===========================================================================;;
35
;; in_addr_t __stdcall inet_addr(__in const char* hostname);                 ;;
36
inet_addr:                                                                   ;;
37
;;---------------------------------------------------------------------------;;
38
;? Convert the string from standard IPv4 dotted notation to integer IP addr. ;;
39
;;---------------------------------------------------------------------------;;
40
;> first parameter = host name                                               ;;
41
;;---------------------------------------------------------------------------;;
42
;< eax = IP address on success / -1 on error                                 ;;
43
;;===========================================================================;;
44
; 0. Save used registers for __stdcall.
45
	push	ebx esi edi
46
	mov	esi, [esp+16]	; esi = hostname
47
; 1. Check that only allowed symbols are present.
48
; (hex digits, possibly letters 'x'/'X' and up to 3 dots)
49
	push	esi
50
	xor	ecx, ecx
51
.calcdots_loop:
52
; loop for all characters in string
53
	lodsb
54
; check for end of string
55
	cmp	al, 0
56
	jz	.calcdots_loop_done
57
; check for dot
58
	cmp	al, '.'
59
	jz	.dot
60
; check for digit
61
	sub	al, '0'
62
	cmp	al, 9
63
	jbe	.calcdots_loop
64
; check for hex letter
65
	sub	al, 'A' - '0'	; 'A'-'F' -> 0-5, 'a'-'f' -> 20h-25h
66
	and	al, not 20h
67
	cmp	al, 'F' - 'A'
68
	jbe	.calcdots_loop
69
; check for 'x'/'X'
70
	cmp	al, 'X' - 'A'
71
	jz	.calcdots_loop
72
	jmp	.fail.pop
73
.dot:
74
	inc	ecx
75
	jmp	.calcdots_loop
76
.calcdots_loop_done:
77
	cmp	ecx, 4
78
	jae	.fail.pop
79
; 2. The name can be valid dotted name; try to convert, checking limit
80
	pop	esi
81
	xor	edi, edi	; edi = address
82
	push	0xFFFFFFFF
83
	pop	edx		; edx = mask for rest of address
84
; 2a. Convert name except for last group.
85
	jecxz	.ip_convert_2b
86
.ip_convert_2a:
87
	push	ecx
88
	mov	ecx, 0xFF	; limit for all groups except for last
89
	call	.get_number
90
	pop	ecx
91
	jc	.fail
92
	cmp	byte [esi-1], '.'
93
	jnz	.fail
94
	shl	edi, 8
95
	shr	edx, 8
96
	add	edi, eax
97
	loop	.ip_convert_2a
98
; 2b. Convert last group.
99
.ip_convert_2b:
100
	mov	ecx, edx
101
	call	.get_number
102
	jc	.fail
103
	cmp	byte [esi-1], 0
104
	jnz	.fail
105
@@:
106
	shl	edi, 8
107
	shr	edx, 8
108
	jnz	@b
109
	add	edi, eax
110
; 2c. Convert to network byte order.
111
	bswap	edi
112
; 3. Set return value, restore used registers and return.
113
	xchg	eax, edi
114
.ret:
115
	pop	edi esi ebx
116
	ret	4
117
; 4. On error, return -1.
118
.fail.pop:
119
	pop	esi
120
.fail:
121
	push	-1
122
	pop	eax
123
	jmp	.ret
124
 
125
;;===========================================================================;;
126
;; Internal auxiliary function for IP parsing.                                        ;;
127
.get_number:                                                                 ;;
128
;;---------------------------------------------------------------------------;;
129
;? Converts string to number.                                                ;;
130
;;---------------------------------------------------------------------------;;
131
;> esi -> string                                                             ;;
132
;> ecx = limit for number                                                    ;;
133
;;---------------------------------------------------------------------------;;
134
;< eax = number                                                              ;;
135
;< CF set on error (too big number) / cleared on success                     ;;
136
;< esi -> end of number representation                                       ;;
137
;;===========================================================================;;
138
; 0. Save edx, which is used in caller.
139
	push	edx
140
; 1. Initialize number, zero eax so that lodsb gets full dword.
141
	xor	eax, eax
142
	xor	edx, edx
143
; 2. Get used numeral system: 0x = hex, otherwise 0 = octal, otherwise decimal
144
	push	10
145
	pop	ebx
146
	lodsb
147
	cmp	al, '0'
148
	jnz	.convert
149
	push	8
150
	pop	ebx
151
	lodsb
152
	cmp	al, 'x'
153
	jnz	.convert
154
	add	ebx, ebx
155
; 3. Loop while digits are encountered.
156
.convert:
157
; 4. Convert digit from text representation to binary value.
158
	or	al, 20h	; '0'-'9' -> '0'-'9', 'A'-'F' -> 'a'-'f'
159
	sub	al, '0'
160
	cmp	al, 9
161
	jbe	.digit
162
	sub	al, 'a' - '0'
163
	cmp	al, 'f' - 'a'
164
	ja	.convert_done
165
	add	al, 10
166
.digit:
167
; 5. Digit must be less than base of numeral system.
168
	cmp	eax, ebx
169
	jae	.convert_done
170
; 6. Advance the number.
171
	imul	edx, ebx
172
	add	edx, eax
173
	cmp	edx, ecx
174
	ja	.gn_error
175
; 3b. Continue loop.
176
	lodsb
177
	jmp	.convert
178
.convert_done:
179
; 7. Invalid character, number converted, return success.
180
	xchg	eax, edx
181
	pop	edx
182
	clc
183
	ret
184
.gn_error:
185
; 8. Too big number, return error.
186
	pop	edx
187
	stc
188
	ret
189
 
190
;;===========================================================================;;
191
;; char* __stdcall inet_ntoa(struct in_addr in);                             ;;
192
inet_ntoa:                                                                   ;;
193
;;---------------------------------------------------------------------------;;
194
;? Convert the Internet host address to standard IPv4 dotted notation.       ;;
195
;;---------------------------------------------------------------------------;;
196
;> first parameter = host address                                            ;;
197
;;---------------------------------------------------------------------------;;
198
;< eax = pointer to resulting string (in static buffer)                      ;;
199
;;===========================================================================;;
200
; 0. Save used registers for __stdcall.
201
	push	ebx esi edi
202
	mov	bl, 0xCD	; constant for div 10
203
; 1. Write octet 4 times.
204
	mov	edi, .buffer
205
	mov	edx, [esp+16]	; eax = in
206
	mov	al, dl
207
	call	.write
208
	mov	al, dh
209
	shr	edx, 16
210
	call	.write
211
	mov	al, dl
212
	call	.write
213
	mov	al, dh
214
	call	.write
215
; 2. Replace final dot with terminating zero.
216
	mov	byte [edi-1], 0
217
; 3. Restore used registers, set result value and return.
218
	pop	edi esi ebx
219
	mov	eax, .buffer
220
	ret	4
221
 
222
.write:
223
	movzx	esi, al
224
	mul	bl
225
	add	esi, ('.' shl 8) + '0'
226
	shr	ah, 3	; ah = al / 10
227
	movzx	ecx, ah
228
	add	ecx, ecx
229
	lea	ecx, [ecx*5]
230
	sub	esi, ecx	; lobyte(esi) = al % 10, hibyte(esi) = '.'
231
	test	ah, ah
232
	jz	.1digit
233
	cmp	ah, 10
234
	jb	.2digit
235
	cmp	ah, 20
236
	sbb	cl, cl
237
	add	cl, '2'
238
	mov	byte [edi], cl
239
	movzx	ecx, cl
240
	lea	ecx, [ecx*5]
241
	sub	ah, cl
242
	sub	ah, cl
243
	add	ah, ('0'*11) and 255
244
	mov	byte [edi+1], ah
245
	mov	word [edi+2], si
246
	add	edi, 4
247
	ret
248
.2digit:
249
	add	ah, '0'
250
	mov	byte [edi], ah
251
	mov	word [edi+1], si
252
	add	edi, 3
253
	ret
254
.1digit:
255
	mov	word [edi], si
256
	add	edi, 2
257
	ret
258
 
259
struct __gai_reqdata
260
	socket	dd	?
261
; external code should not look on rest of this structure,
262
; it is internal for getaddrinfo_start/process/abort
263
	reqid		dw	?	; DNS request ID
264
	socktype	db	?	; SOCK_* or 0 for any
265
			db	?
266
	service		dd	?
267
	flags		dd	?
268
	reserved	rb	16
269
ends
270
 
271
;;===========================================================================;;
272
;; int __stdcall getaddrinfo(__in const char* hostname,                      ;;
273
;;                           __in const char* servname,                      ;;
274
;;                           __in const struct addrinfo* hints,              ;;
275
;;                           __out struct addrinfo **res);                   ;;
276
getaddrinfo:                                                                 ;;
277
;;---------------------------------------------------------------------------;;
278
;? Get a list of IP addresses and port numbers for given host and service    ;;
279
;;---------------------------------------------------------------------------;;
280
;> first parameter (optional) = host name                                    ;;
281
;> second parameter (optional) = service name (decimal number for now)       ;;
282
;> third parameter (optional) = hints for socket type                        ;;
283
;> fourth parameter = pointer to result (head of L1-list)                    ;;
284
;;---------------------------------------------------------------------------;;
285
;< eax = 0 on success / one of EAI_ codes on error                           ;;
286
;;===========================================================================;;
287
; 0. Save used registers for __stdcall.
288
	push	ebx esi edi
289
	mov	edi, [esp+28]	; edi = res
290
; 1. Create and send DNS packet.
291
	sub	esp, sizeof.__gai_reqdata	; reserve stack place (1)
292
	push	esp		; fifth parameter = pointer to (1)
293
	push	edi		; fourth parameter = res
294
	push	dword [esp+32+sizeof.__gai_reqdata]	; third parameter = hints
295
	push	dword [esp+32+sizeof.__gai_reqdata]	; second parameter = servname
296
	push	dword [esp+32+sizeof.__gai_reqdata]	; first parameter = hostname
297
	call	getaddrinfo_start
298
	test	eax, eax
299
	jns	.ret	; if name resolved without network activity, return
300
; 2. Wait for DNS reply.
301
; 2a. Ignore all events except network stack.
302
	mcall	40, EVM_STACK
303
	push	eax	; save previous event mask (2)
304
; 2b. Get upper limit for wait time. Use timeout = 5 seconds.
305
	mcall	26, 9	; get time stamp
306
	xchg	esi, eax	; save time stamp to esi
307
	mov	ebx, 500	; start value for timeout
308
	add	esi, ebx
309
.wait:
310
; 2c. Wait for event with timeout.
311
	mcall	23	; wait for event - must be stack event
312
; 2d. Check for timeout.
313
	test	eax, eax
314
	lea	eax, [esp+4]	; pointer to (1)
315
	jz	.timeout
316
; 3. Got packet. Call processing function.
317
	push	edi	; second parameter: pointer to result
318
	push	eax	; first parameter: pointer to reqdata
319
	call	getaddrinfo_process
320
; 4. Test whether wait loop must be continued.
321
	test	eax, eax
322
	jns	.ret.restore
323
; 2e. Recalculate timeout value.
324
	mcall	26, 9
325
	mov	ebx, esi
326
	sub	ebx, eax
327
; 2f. Check that time is not over; if not, continue wait loop
328
	cmp	ebx, 500
329
	jbe	.wait
330
.timeout:
331
; 5. Timeout: abort and return error
332
	push	eax
333
	call	getaddrinfo_abort
334
	and	dword [edi], 0
335
	push	EAI_AGAIN
336
	pop	eax
337
.ret.restore:
338
; 6. Restore event mask.
339
	pop	ebx	; get event mask (2)
340
	push	eax	; save return code (3)
341
	mcall	40
342
	pop	eax	; restore return code (3)
343
.ret:
344
; 7. Restore stack pointer, used registers and return.
345
	add	esp, sizeof.__gai_reqdata	; undo (1)
346
	pop	edi esi ebx
347
	ret	16
348
 
349
;;===========================================================================;;
350
;; int __stdcall getaddrinfo_start(__in const char* hostname,                ;;
351
;;                                 __in const char* servname,                ;;
352
;;                                 __in const struct addrinfo* hints,        ;;
353
;;                                 __out struct addrinfo **res,              ;;
354
;;                                 __out struct __gai_reqdata* reqdata);     ;;
355
getaddrinfo_start:                                                           ;;
356
;;---------------------------------------------------------------------------;;
357
;? Initiator for getaddrinfo, sends DNS request                              ;;
358
;;---------------------------------------------------------------------------;;
359
;> first 4 parameters same as for getaddrinfo                                ;;
360
;> last parameter = pointer to buffer for __gai_reqdata, must be passed to   ;;
361
;>                  getaddrinfo_process as is                                ;;
362
;;---------------------------------------------------------------------------;;
363
;< eax = <0 if wait loop must be entered / 0 on success / EAI_* on error     ;;
364
;;===========================================================================;;
365
;; Known limitations:                                                        ;;
366
;; 1. No support for TCP connections =>                                      ;;
367
;; 1a. Long replies will be truncated, and not all IP addresses will be got. ;;
368
;; 2. No support for iterative resolving =>                                  ;;
369
;; 2a. In theory may fail with some servers.                                 ;;
370
;; 3. Assumes that domain for relative names is always root, ".".            ;;
371
;; 4. Does not support lookup of services by name,                           ;;
372
;;    only decimal representation is supported.                              ;;
373
;; 5. Assumes that IPv4 is always configured, so AI_ADDRCONFIG has no effect.;;
374
;;===========================================================================;;
375
; 0. Create stack frame and save used registers for __stdcall.
376
	push	ebx esi edi
377
	push	ebp
378
	mov	ebp, esp
379
virtual at ebp-8
380
.recent_restsize dd	?	; this is for memory alloc in ._.generate_data
381
.recent_page	dd	?	; this is for memory alloc in ._.generate_data
382
	rd	5	; saved regs and return address
383
.hostname	dd	?
384
.servname	dd	?
385
.hints		dd	?
386
.res		dd	?
387
.reqdata	dd	?
388
end virtual
389
	xor	edi, edi
390
	push	edi	; init .recent_page
391
	push	edi	; init .recent_restsize
392
; 1. Check that parameters are correct and can be handled by this implementation.
393
; 1a. If 'res' pointer is given, set result to zero.
394
	mov	eax, [.res]
395
	test	eax, eax
396
	jz	@f
397
	mov	[eax], edi
398
@@:
399
; 1b. Only AI_SUPPORTED flags are supported for hints->ai_flags.
400
	mov	ecx, [.hints]
401
	xor	edx, edx
402
	jecxz	.nohints
403
	mov	edx, [ecx+addrinfo.ai_flags]
404
.nohints:
405
	mov	ebx, [.reqdata]
406
	mov	[ebx+__gai_reqdata.flags], edx
407
	push	EAI_BADFLAGS
408
	pop	eax
409
	test	edx, not AI_SUPPORTED
410
	jnz	.ret
411
; 1c. Either hostname or servname must be given. If AI_CANONNAME is set,
412
; hostname must also be set.
413
	cmp	[.hostname], edi
414
	jnz	@f
415
	test	dl, AI_CANONNAME
416
	jnz	.ret
417
	push	EAI_NONAME
418
	pop	eax
419
	cmp	[.servname], edi
420
	jz	.ret
421
@@:
422
; 1d. Only IPv4 is supported, so hints->ai_family must be either PF_UNSPEC or PF_INET.
423
	push	EAI_FAMILY
424
	pop	eax
425
	jecxz	@f
426
	cmp	[ecx+addrinfo.ai_family], edi
427
	jz	@f
428
	cmp	[ecx+addrinfo.ai_family], PF_INET
429
	jnz	.ret
430
@@:
431
; 1e. Valid combinations for ai_socktype/ai_protocol: 0/0 for any or
432
;	SOCK_STREAM/IPPROTO_TCP, SOCK_DGRAM/IPPROTO_UDP
433
;	(raw sockets are not yet supported by the kernel)
434
	xor	edx, edx	; assume 0=any if no hints
435
	jecxz	.socket_type_ok
436
	mov	edx, [ecx+addrinfo.ai_socktype]
437
	mov	esi, [ecx+addrinfo.ai_protocol]
438
; 1f. Test for ai_socktype=0 and ai_protocol=0.
439
	test	edx, edx
440
	jnz	.check_socktype
441
	test	esi, esi
442
	jz	.socket_type_ok
443
; 1g. ai_socktype=0, ai_protocol is nonzero.
444
	push	EAI_SERVICE
445
	pop	eax
446
	inc	edx	; edx = SOCK_STREAM
447
	cmp	esi, IPPROTO_TCP
448
	jz	.socket_type_ok
449
	inc	edx	; edx = SOCK_DGRAM
450
	cmp	esi, IPPROTO_UDP
451
	jz	.socket_type_ok
452
.ret:
453
; Restore saved registers, destroy stack frame and return.
454
	mov	esp, ebp
455
	pop	ebp
456
	pop	edi esi ebx
457
	ret	20
458
; 1h. ai_socktype is nonzero.
459
.check_socktype:
460
	push	EAI_SOCKTYPE
461
	pop	eax
462
	cmp	edx, SOCK_STREAM
463
	jz	.check_tcp
464
	cmp	edx, SOCK_DGRAM
465
	jnz	.ret
466
	test	esi, esi
467
	jz	.socket_type_ok
468
	cmp	esi, IPPROTO_UDP
469
	jz	.socket_type_ok
470
	jmp	.ret
471
.check_tcp:
472
	test	esi, esi
473
	jz	.socket_type_ok
474
	cmp	esi, IPPROTO_TCP
475
	jnz	.ret
476
.socket_type_ok:
477
	mov	[ebx+__gai_reqdata.socktype], dl
478
; 2. Resolve service.
479
; 2a. If no name is given, remember value -1.
480
	push	-1
481
	pop	edx
482
	mov	esi, [.servname]
483
	test	esi, esi
484
	jz	.service_resolved
485
; 2b. Loop for characters of string while digits are encountered.
486
	xor	edx, edx
487
	xor	eax, eax
488
.serv_to_number:
489
	lodsb
490
	sub	al, '0'
491
	cmp	al, 9
492
	ja	.serv_to_number_done
493
; for each digit, set edx = edx*10 + 
494
	lea	edx, [edx*5]
495
	lea	edx, [edx*2+eax]
496
; check for correctness: service port must fit in word
497
	cmp	edx, 0x10000
498
	jae	.service_not_number
499
	jmp	.serv_to_number
500
.serv_to_number_done:
501
	and	edx, 0xFFFF	; make sure that port fits
502
; 2c. If zero character reached, name is resolved;
503
; otherwise, return error (no support for symbolic names yet)
504
	cmp	al, -'0'
505
	jz	.service_resolved
506
.service_not_number:
507
	push	EAI_NONAME
508
	pop	eax
509
	jmp	.ret
510
.service_resolved:
511
; 2d. Save result to reqdata.
512
	mov	[ebx+__gai_reqdata.service], edx
513
; 3. Process host name.
514
	mov	esi, [.hostname]
515
; 3a. If hostname is not given,
516
;	use localhost for active sockets and INADDR_ANY for passive sockets.
517
	mov	eax, 0x0100007F	; 127.0.0.1 in network byte order
518
	test	byte [ebx+__gai_reqdata.flags], AI_PASSIVE
519
	jz	@f
520
	xor	eax, eax
521
@@:
522
	test	esi, esi
523
	jz	.hostname_is_ip
524
; 3b. Check for dotted IPv4 name.
525
	push	esi
526
	call	inet_addr
527
	cmp	eax, -1
528
	jz	.resolve_hostname
529
.hostname_is_ip:
530
; 3c. hostname is valid representation of IP address, and we have resolved it.
531
; Generate result, if .res pointer is not NULL.
532
	mov	ebx, [.reqdata]
533
	mov	esi, [.res]
534
	test	esi, esi
535
	jz	.no_result
536
	call	getaddrinfo._.generate_data
537
; 3d. Check for memory allocation error.
538
.3d:
539
	push	EAI_MEMORY
540
	pop	eax
541
	test	esi, esi
542
	jz	.ret
543
; 3e. If AI_CANONNAME is set, copy input name.
544
	test	byte [ebx+__gai_reqdata.flags], AI_CANONNAME
545
	jz	.no_result
546
; 3f. Calculate length of name.
547
	push	-1
548
	pop	ecx
549
	mov	edi, [.hostname]
550
	xor	eax, eax
551
	repnz	scasb
552
	not	ecx
553
; 3g. Check whether it fits on one page with main data.
554
	cmp	ecx, [.recent_restsize]
555
	jbe	.name_fits
556
; 3h. If not, allocate new page.
557
	push	ecx
558
	add	ecx, 4	; first dword contains number of objects on the page
559
	mcall	68, 12
560
	pop	ecx
561
; 3i. If allocation has failed, free addrinfo and return error.
562
	test	eax, eax
563
	jnz	.name_allocated
564
	push	[.res]
565
	call	freeaddrinfo
566
	push	EAI_MEMORY
567
	pop	eax
568
	jmp	.ret
569
.name_allocated:
570
; 3j. Otherwise, set edi to allocated memory and continue to 3l.
571
	xchg	edi, eax	; put result to edi
572
	push	1
573
	pop	eax
574
	stosd	; number of objects on the page = 1
575
	jmp	.copy_name
576
.name_fits:
577
; 3k. Get pointer to free memory in allocated page.
578
	mov	edi, [.recent_page]
579
	mov	eax, edi
580
	and	eax, not 0xFFF
581
	inc	dword [eax]	; increase number of objects
582
.copy_name:
583
; 3l. Put pointer to struct addrinfo.
584
	mov	eax, [.res]
585
	mov	eax, [eax]
586
	mov	[eax+addrinfo.ai_canonname], edi
587
; 3m. Copy name.
588
	rep	movsb
589
.no_result:
590
; 3n. Return success.
591
	xor	eax, eax
592
	jmp	.ret
593
; 4. Host address is not dotted IP. Test whether we are allowed to contact DNS.
594
; Return error if no.
595
.resolve_hostname:
596
	push	EAI_NONAME
597
	pop	eax
598
	mov	ebx, [.reqdata]
599
	test	byte [ebx+__gai_reqdata.flags], AI_NUMERICHOST
600
	jnz	.ret
601
; Host address is domain name. Contact DNS server.
602
	mov	esi, [.hostname]
603
; 5. Reserve stack place for UDP packet.
604
; According to RFC1035, maximum UDP packet size in DNS is 512 bytes.
605
	sub	esp, 512
606
; 6. Create DNS request packet.
607
; 6a. Set pointer to start of buffer.
608
	mov	edi, esp
609
; 6b. Get request ID, write it to buffer.
610
	push	1
611
	pop	eax
612
lock	xadd	[DNSrequestID], eax	; atomically increment ID, get old value
613
	stosw
614
	mov	[ebx+__gai_reqdata.reqid], ax
615
; 6c. Packed field: QR=0 (query), Opcode=0000 (standard query),
616
;	AA=0 (ignored in requests), TC=0 (no truncation),
617
;	RD=1 (recursion desired)
618
	mov	al, 00000001b
619
	stosb
620
; 6d. Packed field: ignored in requests
621
	mov	al, 0
622
	stosb
623
; 6e. Write questions count = 1 and answers count = 0
624
; Note that network byte order is big-endian.
625
	mov	eax, 0x00000100
626
	stosd
627
; 6f. Write nameservers count = 0 and additional records count = 0
628
	xor	eax, eax
629
	stosd
630
; 6g. Write request data: name
631
; According to RFC1035, maximum length of name is 255 bytes.
632
; For correct names, buffer cannot overflow.
633
	lea	ebx, [esi+256]	; ebx = limit for name (including terminating zero)
634
; translate string "www.yandex.ru" {00} to byte data {03} "www" {06} "yandex" {02} "ru" {00}
635
.nameloop:	; here we go in the start of each label: before "www", before "yandex", before "ru"
636
	xor	ecx, ecx	; ecx = length of current label
637
	inc	edi	; skip length, it will be filled later
638
.labelloop:	; here we go for each symbol of name
639
	lodsb	; get next character
640
	test	al, al	; terminating zero?
641
	jz	.endname
642
	cmp	esi, ebx	; limit exceeded?
643
	jae	.wrongname
644
	cmp	al, '.'	; end of label?
645
	jz	.labelend
646
	stosb	; put next character
647
	inc	ecx	; increment label length
648
	jmp	.labelloop
649
.wrongname:
650
	push	EAI_NONAME
651
	pop	eax
652
	jmp	.ret
653
.labelend:
654
	test	ecx, ecx	; null label can be only in the end of name
655
	jz	.wrongname
656
.endname:
657
	cmp	ecx, 63
658
	ja	.wrongname
659
; write length to byte [edi-ecx-1]
660
	mov	eax, ecx
661
	neg	eax
662
	mov	byte [edi+eax-1], cl
663
	cmp	byte [esi-1], 0	; that was last label in the name?
664
	jnz	.nameloop
665
; write terminating zero if not yet
666
	mov	al, 0
667
	cmp	byte [edi-1], al
668
	jz	@f
669
	stosb
670
@@:
671
; 6h. Write request data:
672
;	query type = A (host address) = 1,
673
;	query class = IN (internet IPv4 address) = 1
674
; Note that network byte order is big-endian.
675
	mov	eax, 0x01000100
676
	stosd
677
; 7. Get DNS server address.
678
	mcall	52, 13
679
	xchg	esi, eax	; put server address to esi
680
; 8. Open UDP socket to DNS server, port 53.
681
	mcall	53, 0, 0, 53
682
	cmp	eax, -1	; error?
683
	jz	.ret.dnserr
684
	xchg	ecx, eax	; put socket handle to ecx
685
; 9. Send DNS request packet.
686
	sub	edi, esp	; get packet length
687
	mcall	53, 4, , edi, esp
688
	cmp	eax, -1
689
	jz	.ret.close
690
	mov	eax, [.reqdata]
691
	mov	[eax+__gai_reqdata.socket], ecx
692
	push	-1
693
	pop	eax	; return status: more processing required
694
	jmp	.ret.dns
695
.ret.close:
696
	mcall	53, 1
697
.ret.dnserr:
698
	push	EAI_AGAIN
699
	pop	eax
700
.ret.dns:
701
; 6. Restore stack pointer and return.
702
	jmp	.ret
703
 
704
;;===========================================================================;;
705
;; int __stdcall getaddrinfo_process(__in struct __gai_reqdata* reqdata,     ;;
706
;;                                   __out struct addrinfo** res);           ;;
707
getaddrinfo_process:                                                         ;;
708
;;---------------------------------------------------------------------------;;
709
;? Processes network events from DNS reply                                   ;;
710
;;---------------------------------------------------------------------------;;
711
;> first parameter = pointer to struct __gai_reqdata filled by ..._start     ;;
712
;> second parameter = same as for getaddrinfo                                ;;
713
;;---------------------------------------------------------------------------;;
714
;< eax = -1 if more processing required / 0 on success / >0 = error code     ;;
715
;;===========================================================================;;
716
; 0. Create stack frame.
717
	push	ebp
718
	mov	ebp, esp
719
virtual at ebp-.locals_size
720
.locals_start:
721
.datagram	rb	512
722
.addrname	dd	?
723
.name		dd	?
724
.res_list_tail	dd	?
725
.cname		dd	?
726
.recent_restsize dd	?	; this is for memory alloc in ._.generate_data
727
.recent_page	dd	?	; this is for memory alloc in ._.generate_data
728
.locals_size = $ - .locals_start
729
		rd	2
730
.reqdata	dd	?
731
.res		dd	?
732
end virtual
733
	xor	eax, eax
734
	push	eax	; initialize .recent_page
735
	push	eax	; initialize .recent_restsize
736
	push	eax	; initialize .cname
737
	push	[.res]	; initialize .res_list_tail
738
	sub	esp, .locals_size-16	; reserve place for other vars
739
	mov	edx, esp	; edx -> buffer for datagram
740
; 1. Save used registers for __stdcall.
741
	push	ebx esi edi
742
	mov	edi, [.reqdata]
743
; 2. Read UDP datagram.
744
	mov	ecx, [edi+__gai_reqdata.socket]
745
	mcall	53, 11, , , 512
746
; 3. Ignore events for other sockets (return if no data read)
747
	test	eax, eax
748
	jz	.ret.more_processing_required
749
; 4. Sanity check: discard too short packets.
750
	xchg	ecx, eax	; save packet length in ecx
751
	cmp	ecx, 12
752
	jb	.ret.more_processing_required
753
; 5. Discard packets with ID != request ID.
754
	mov	eax, dword [edi+__gai_reqdata.reqid]
755
	cmp	ax, [edx]
756
	jnz	.ret.more_processing_required
757
; 6. Sanity check: discard query packets.
758
	test	byte [edx+2], 80h
759
	jz	.ret.more_processing_required
760
; 7. Sanity check: must be exactly one query (our).
761
	cmp	word [edx+4], 0x0100	; note network byte order
762
	jnz	.ret.more_processing_required
763
; 8. Check for errors. Return EAI_NONAME for error code 3 and EAI_FAIL for other.
764
	mov	al, [edx+3]
765
	and	al, 0xF
766
	jz	@f
767
	cmp	al, 3
768
	jnz	.ret.no_recovery
769
	jmp	.ret.no_name
770
@@:
771
; 9. Locate answers section. Exactly 1 query is present in this packet.
772
	add	ecx, edx	; ecx = limit
773
	lea	esi, [edx+12]
774
	call	.skip_name
775
	lodsd		; skip QTYPE and QCLASS field
776
	cmp	esi, ecx
777
	ja	.ret.no_recovery
778
; 10. Loop through all answers.
779
	movzx	ebx, word [edx+6]	; get answers count
780
	xchg	bl, bh		; network -> Intel byte order
781
.answers_loop:
782
	dec	ebx
783
	js	.answers_done
784
; 10a. Process each record.
785
	mov	[.name], esi
786
; 10b. Skip name field.
787
	call	.skip_name
788
; 10c. Get record information, handle two types for class IN (internet).
789
	lodsd		; get type and class
790
	cmp	esi, ecx
791
	ja	.ret.no_recovery
792
	cmp	eax, 0x01000500	; type=5, class=1?
793
	jz	.got_cname
794
	cmp	eax, 0x01000100	; type=1, class=1?
795
	jnz	.answers_loop.next
796
.got_addr:
797
; 10d. Process record A, host address.
798
	add	esi, 10
799
	cmp	esi, ecx
800
	ja	.ret.no_recovery
801
	cmp	word [esi-6], 0x0400	; RDATA for A records must be 4 bytes long
802
	jnz	.ret.no_recovery
803
	mov	eax, [.name]
804
	mov	[.addrname], eax
805
; 10e. Create corresponding record in the answer.
806
	push	ebx ecx esi
807
	mov	eax, [esi-4]	; IP address
808
	mov	esi, [.res_list_tail]	; pointer to result
809
	test	esi, esi
810
	jz	.no_result	; do not save if .res is NULL
811
	mov	ebx, [.reqdata]	; request data
812
	call	getaddrinfo._.generate_data
813
	mov	[.res_list_tail], esi
814
	pop	esi ecx ebx
815
	cmp	[.res_list_tail], 0
816
	jnz	.answers_loop
817
; 10f. If generate_data failed (this means memory allocation failure), abort
818
	jmp	.ret.no_memory
819
.no_result:
820
	pop	esi ecx ebx
821
	jmp	.answers_loop
822
.got_cname:
823
; 10g. Process record CNAME, main host name.
824
	lea	eax, [esi+6]
825
	mov	[.cname], eax
826
.answers_loop.next:
827
; 10h. Skip other record fields, advance to next record.
828
	lodsd	; skip TTL
829
	xor	eax, eax
830
	lodsw	; get length of RDATA field
831
	xchg	al, ah	; network -> Intel byte order
832
	add	esi, eax
833
	cmp	esi, ecx
834
	ja	.ret.no_recovery
835
	jmp	.answers_loop
836
.answers_done:
837
; 11. Check that there is at least 1 answer.
838
	mov	eax, [.res_list_tail]
839
	cmp	[.res], eax
840
	jz	.ret.no_data
841
; 12. If canonical name was required, add it now.
842
	mov	eax, [.reqdata]
843
	test	byte [eax+__gai_reqdata.flags], AI_CANONNAME
844
	jz	.no_canon_name
845
; 12a. If at least one CNAME record is present, use name from last such record.
846
; Otherwise, use name from one of A records.
847
	mov	esi, [.cname]
848
	test	esi, esi
849
	jnz	.has_cname
850
	mov	esi, [.addrname]
851
.has_cname:
852
; 12b. Calculate name length.
853
	call	.get_name_length
854
	jc	.ret.no_recovery
855
; 12c. Check that the caller really want to get data.
856
	cmp	[.res], 0
857
	jz	.no_canon_name
858
; 12d. Allocate memory for name.
859
	call	getaddrinfo._.memalloc
860
	test	edi, edi
861
	jz	.ret.no_memory
862
; 12e. Make first entry in .res list point to canonical name.
863
	mov	eax, [.res]
864
	mov	eax, [eax]
865
	mov	[eax+addrinfo.ai_canonname], edi
866
; 12f. Decode name.
867
	call	.decode_name
868
.no_canon_name:
869
; 13. Set status to success.
870
	xor	eax, eax
871
	jmp	.ret.close
872
; Handle errors.
873
.ret.more_processing_required:
874
	push	-1
875
	pop	eax
876
	jmp	.ret
877
.ret.no_recovery:
878
	push	EAI_FAIL
879
	pop	eax
880
	jmp	.ret.destroy
881
.ret.no_memory:
882
	push	EAI_MEMORY
883
	pop	eax
884
	jmp	.ret.destroy
885
.ret.no_name:
886
.ret.no_data:
887
	push	EAI_NONAME
888
	pop	eax
889
.ret.destroy:
890
; 14. If an error occured, free memory acquired so far.
891
	push	eax
892
	mov	esi, [.res]
893
	test	esi, esi
894
	jz	@f
895
	pushd	[esi]
896
	call	freeaddrinfo
897
	and	dword [esi], 0
898
@@:
899
	pop	eax
900
.ret.close:
901
; 15. Close socket.
902
	push	eax
903
	mov	ecx, [.reqdata]
904
	mov	ecx, [ecx+__gai_reqdata.socket]
905
	mcall	53, 1
906
	pop	eax
907
; 16. Restore used registers, destroy stack frame and return.
908
.ret:
909
	pop	edi esi ebx
910
	mov	esp, ebp
911
	pop	ebp
912
	ret	8
913
 
914
;;===========================================================================;;
915
;; Internal auxiliary function for skipping names in DNS packet.             ;;
916
.skip_name:                                                                  ;;
917
;;---------------------------------------------------------------------------;;
918
;? Skips name in DNS packet.                                                 ;;
919
;;---------------------------------------------------------------------------;;
920
;> esi -> name                                                               ;;
921
;> ecx = end of packet                                                       ;;
922
;;---------------------------------------------------------------------------;;
923
;< esi -> end of name                                                        ;;
924
;;===========================================================================;;
925
	xor	eax, eax
926
	cmp	esi, ecx
927
	jae	.skip_name.done
928
	lodsb
929
	test	al, al
930
	jz	.skip_name.done
931
	test	al, 0xC0
932
	jnz	.skip_name.pointer
933
	add	esi, eax
934
	jmp	.skip_name
935
.skip_name.pointer:
936
	inc	esi
937
.skip_name.done:
938
	ret
939
 
940
;;===========================================================================;;
941
;; Internal auxiliary function for calculating length of name in DNS packet. ;;
942
.get_name_length:                                                            ;;
943
;;---------------------------------------------------------------------------;;
944
;? Calculate length of name (including terminating zero) in DNS packet.      ;;
945
;;---------------------------------------------------------------------------;;
946
;> edx = start of packet                                                     ;;
947
;> esi -> name                                                               ;;
948
;> ecx = end of packet                                                       ;;
949
;;---------------------------------------------------------------------------;;
950
;< eax = length of name                                                      ;;
951
;< CF set on error / cleared on success                                      ;;
952
;;===========================================================================;;
953
	xor	ebx, ebx	; ebx will hold data length
954
.get_name_length.zero:
955
	xor	eax, eax
956
.get_name_length.loop:
957
	cmp	esi, ecx
958
	jae	.get_name_length.fail
959
	lodsb
960
	test	al, al
961
	jz	.get_name_length.done
962
	test	al, 0xC0
963
	jnz	.get_name_length.pointer
964
	add	esi, eax
965
	inc	ebx
966
	add	ebx, eax
967
	cmp	ebx, 256
968
	jbe	.get_name_length.loop
969
.get_name_length.fail:
970
	stc
971
	ret
972
.get_name_length.pointer:
973
	and	al, 0x3F
974
	mov	ah, al
975
	lodsb
976
	lea	esi, [edx+eax]
977
	jmp	.get_name_length.zero
978
.get_name_length.done:
979
	test	ebx, ebx
980
	jz	.get_name_length.fail
981
	xchg	eax, ebx
982
	clc
983
	ret
984
 
985
;;===========================================================================;;
986
;; Internal auxiliary function for decoding DNS name.                        ;;
987
.decode_name:                                                                ;;
988
;;---------------------------------------------------------------------------;;
989
;? Decode name in DNS packet.                                                ;;
990
;;---------------------------------------------------------------------------;;
991
;> edx = start of packet                                                     ;;
992
;> esi -> name in packet                                                     ;;
993
;> edi -> buffer for decoded name                                            ;;
994
;;===========================================================================;;
995
	xor	eax, eax
996
	lodsb
997
	test	al, al
998
	jz	.decode_name.done
999
	test	al, 0xC0
1000
	jnz	.decode_name.pointer
1001
	mov	ecx, eax
1002
	rep	movsb
1003
	mov	al, '.'
1004
	stosb
1005
	jmp	.decode_name
1006
.decode_name.pointer:
1007
	and	al, 0x3F
1008
	mov	ah, al
1009
	lodsb
1010
	lea	esi, [edx+eax]
1011
	jmp	.decode_name
1012
.decode_name.done:
1013
	mov	byte [edi-1], 0
1014
	ret
1015
 
1016
;;===========================================================================;;
1017
;; Internal auxiliary function for allocating memory for getaddrinfo.        ;;
1018
getaddrinfo._.memalloc:                                                      ;;
1019
;;---------------------------------------------------------------------------;;
1020
;? Memory allocation.                                                        ;;
1021
;;---------------------------------------------------------------------------;;
1022
;> eax = size in bytes, must be less than page size.                         ;;
1023
;> [ebp-4] = .recent_page = last allocated page                              ;;
1024
;> [ebp-8] = .recent_restsize = bytes rest in last allocated page            ;;
1025
;;---------------------------------------------------------------------------;;
1026
;< edi -> allocated memory / NULL on error                                   ;;
1027
;;===========================================================================;;
1028
; 1. Set edi to result of function.
1029
	mov	edi, [ebp-4]
1030
; 2. Check whether we need to allocate a new page.
1031
	cmp	eax, [ebp-8]
1032
	jbe	.no_new_page
1033
; 2. Allocate new page if need. Reset edi to new result.
1034
	push	eax ebx
1035
	mcall	68, 12, 0x1000
1036
	xchg	edi, eax	; put result to edi
1037
	pop	ebx eax
1038
; 3. Check returned value of allocator. Fail if it failed.
1039
	test	edi, edi
1040
	jz	.ret
1041
; 4. Update .recent_page and .recent_restsize.
1042
	add	edi, 4
1043
	sub	ecx, 4
1044
	mov	[ebp-4], edi
1045
	mov	[ebp-8], ecx
1046
.no_new_page:
1047
; 5. Increase number of objects on this page.
1048
	push	eax
1049
	mov	eax, edi
1050
	and	eax, not 0xFFF
1051
	inc	dword [eax]
1052
	pop	eax
1053
; 6. Advance last allocated pointer, decrease memory size.
1054
	add	[ebp-4], eax
1055
	sub	[ebp-8], eax
1056
; 7. Return.
1057
.ret:
1058
	ret
1059
 
1060
;;===========================================================================;;
1061
;; Internal auxiliary function for freeing memory for freeaddrinfo.          ;;
1062
getaddrinfo._.memfree:                                                       ;;
1063
;;---------------------------------------------------------------------------;;
1064
;? Free memory.                                                              ;;
1065
;;---------------------------------------------------------------------------;;
1066
;> eax = pointer                                                             ;;
1067
;;===========================================================================;;
1068
; 1. Get start of page.
1069
	mov	ecx, eax
1070
	and	ecx, not 0xFFF
1071
; 2. Decrease number of objects.
1072
	dec	dword [ecx]
1073
; 3. If it goes to zero, free the page.
1074
	jnz	@f
1075
	push	ebx
1076
	mcall	68, 13
1077
	pop	ebx
1078
@@:
1079
; 4. Done.
1080
	ret
1081
 
1082
;;===========================================================================;;
1083
getaddrinfo._.generate_data:                                                 ;;
1084
;;---------------------------------------------------------------------------;;
1085
;? Generate item(s) of getaddrinfo result list by one IP address.            ;;
1086
;;---------------------------------------------------------------------------;;
1087
;> eax = IP address                                                          ;;
1088
;> ebx = request data                                                        ;;
1089
;> esi = pointer to result                                                   ;;
1090
;> [ebp-4] = .recent_page = last allocated page                              ;;
1091
;> [ebp-8] = .recent_restsize = bytes rest in last allocated page            ;;
1092
;;---------------------------------------------------------------------------;;
1093
;< esi = pointer to next list item for result / NULL on error                ;;
1094
;;===========================================================================;;
1095
; 1. If no service is given, append one item with zero port.
1096
; append one item with zero socktype/protocol/port.
1097
	cmp	[ebx+__gai_reqdata.service], -1
1098
	jnz	.has_service
1099
	call	.append_item
1100
; 1a. If neither protocol nor socktype were specified,
1101
;	leave zeroes in socktype and protocol.
1102
	mov	cl, [ebx+__gai_reqdata.socktype]
1103
	test	cl, cl
1104
	jz	.no_socktype
1105
; 1b. Otherwise, set socktype and protocol to desired.
1106
	call	.set_socktype
1107
.no_socktype:
1108
	ret
1109
.has_service:
1110
; 2. If TCP is allowed, append item for TCP.
1111
	cmp	[ebx+__gai_reqdata.socktype], 0
1112
	jz	.tcp_ok
1113
	cmp	[ebx+__gai_reqdata.socktype], SOCK_STREAM
1114
	jnz	.tcp_disallowed
1115
.tcp_ok:
1116
	call	.append_item
1117
	mov	cl, SOCK_STREAM
1118
	call	.set_socktype
1119
	call	.set_port
1120
.tcp_disallowed:
1121
; 3. If UDP is allowed, append item for UDP.
1122
	cmp	[ebx+__gai_reqdata.socktype], 0
1123
	jz	.udp_ok
1124
	cmp	[ebx+__gai_reqdata.socktype], SOCK_DGRAM
1125
	jnz	.udp_disallowed
1126
.udp_ok:
1127
	call	.append_item
1128
	mov	cl, SOCK_DGRAM
1129
	call	.set_socktype
1130
	call	.set_port
1131
.udp_disallowed:
1132
	ret
1133
 
1134
.append_item:
1135
; 1. Allocate memory for struct sockaddr_in and struct addrinfo.
1136
	push	eax
1137
	push	sizeof.addrinfo + sizeof.sockaddr_in
1138
	pop	eax
1139
	call	getaddrinfo._.memalloc
1140
; 2. Check for memory allocation fail.
1141
	test	edi, edi
1142
	jz	.no_memory
1143
; 3. Zero allocated memory.
1144
	push	(sizeof.addrinfo + sizeof.sockaddr_in) / 4
1145
	pop	ecx
1146
	xor	eax, eax
1147
	push	edi
1148
	rep	stosd
1149
	pop	edi
1150
; 4. Fill struct addrinfo.
1151
	mov	eax, [ebx+__gai_reqdata.flags]
1152
	mov	[edi+addrinfo.ai_flags], eax
1153
	mov	byte [edi+addrinfo.ai_family], PF_INET
1154
	mov	byte [edi+addrinfo.ai_addrlen], sizeof.sockaddr_in
1155
	lea	ecx, [edi+sizeof.addrinfo]
1156
	mov	[edi+addrinfo.ai_addr], ecx
1157
; 5. Fill struct sockaddr_in.
1158
	mov	byte [ecx+sockaddr_in.sin_len], sizeof.sockaddr_in
1159
	mov	byte [ecx+sockaddr_in.sin_family], PF_INET
1160
	pop	eax
1161
	mov	[ecx+sockaddr_in.sin_addr], eax
1162
; 6. Append new item to the list.
1163
	mov	[esi], edi
1164
	lea	esi, [edi+addrinfo.ai_next]
1165
; 7. Return.
1166
	ret
1167
.no_memory:
1168
	pop	eax
1169
	xor	esi, esi
1170
	ret
1171
 
1172
.set_socktype:
1173
; Set ai_socktype and ai_protocol fields by given socket type.
1174
	mov	byte [edi+addrinfo.ai_socktype], cl
1175
	dec	cl
1176
	jnz	.set_udp
1177
.set_tcp:
1178
	mov	byte [edi+addrinfo.ai_protocol], IPPROTO_TCP
1179
	ret
1180
.set_udp:
1181
	mov	byte [edi+addrinfo.ai_protocol], IPPROTO_UDP
1182
	ret
1183
 
1184
.set_port:
1185
; Just copy port from input __gai_reqdata to output addrinfo.
1186
	push	edx
1187
	mov	edx, [ebx+__gai_reqdata.service]
1188
	xchg	dl, dh	; convert to network byte order
1189
	mov	[edi+sizeof.addrinfo+sockaddr_in.sin_port], dx
1190
	pop	edx
1191
	ret
1192
 
1193
;;===========================================================================;;
1194
;; void __stdcall getaddrinfo_abort(__in struct __gai_reqdata* reqdata);      ;;
1195
getaddrinfo_abort:                                                           ;;
1196
;;---------------------------------------------------------------------------;;
1197
;? Abort process started by getaddrinfo_start, free all resources.           ;;
1198
;;---------------------------------------------------------------------------;;
1199
;> first parameter = pointer to struct __gai_reqdata filled by ..._start     ;;
1200
;;===========================================================================;;
1201
; 0. Save used registers for __stdcall.
1202
	push	ebx
1203
; 1. Allocated resources: only socket, so close it and return.
1204
	mov	eax, [esp+8]
1205
	mov	ecx, [eax+__gai_reqdata.socket]
1206
	mcall	53, 1
1207
; 2. Restore used registers and return.
1208
	pop	ebx
1209
	ret	4
1210
 
1211
;;===========================================================================;;
1212
;; void __stdcall freeaddrinfo(__in struct addrinfo* ai);                    ;;
1213
freeaddrinfo:                                                                ;;
1214
;;---------------------------------------------------------------------------;;
1215
;? Free one or more addrinfo structures returned by getaddrinfo.             ;;
1216
;;---------------------------------------------------------------------------;;
1217
;> first parameter = head of list of structures                              ;;
1218
;                    (may be arbitrary sublist of original)                  ;;
1219
;;===========================================================================;;
1220
; 1. Loop for all items in the list.
1221
	mov	edx, [esp+4]	; eax = ai
1222
.loop:
1223
	test	edx, edx
1224
	jz	.done
1225
; 2. Free each item.
1226
; 2a. Free ai_canonname, if allocated.
1227
	mov	eax, [edx+addrinfo.ai_canonname]
1228
	test	eax, eax
1229
	jz	.no_canon_name
1230
	call	getaddrinfo._.memfree
1231
.no_canon_name:
1232
; 2b. Remember next item
1233
;	(after freeing the field ai_next can became unavailable).
1234
	pushd	[edx+addrinfo.ai_next]
1235
; 2c. Free item itself.
1236
	xchg	eax, edx
1237
	call	getaddrinfo._.memfree
1238
; 2d. Restore pointer to next item and continue loop.
1239
	pop	edx
1240
	jmp	.loop
1241
.done:
1242
; 3. Done.
1243
	ret	4
1244
 
1245
;;===========================================================================;;
1246
;;///////////////////////////////////////////////////////////////////////////;;
1247
;;===========================================================================;;
1248
;! Exported functions section                                                ;;
1249
;;===========================================================================;;
1250
;;///////////////////////////////////////////////////////////////////////////;;
1251
;;===========================================================================;;
1252
 
1253
 
1254
align 4
1255
@EXPORT:
1256
export	\
1257
	lib_init		, 'lib_init'		, \
1258
	0x00010001		, 'version'		, \
1259
	inet_addr		, 'inet_addr'		, \
1260
	inet_ntoa		, 'inet_ntoa'		, \
1261
	getaddrinfo		, 'getaddrinfo'		, \
1262
	getaddrinfo_start	, 'getaddrinfo_start'	, \
1263
	getaddrinfo_process	, 'getaddrinfo_process'	, \
1264
	getaddrinfo_abort	, 'getaddrinfo_abort'	, \
1265
	freeaddrinfo		, 'freeaddrinfo'
1266
 
1267
; import from libini
1268
align 4
1269
@IMPORT:
1270
 
1271
library	libini, 'libini.obj'
1272
import	libini, \
1273
	ini.get_str, 'ini_get_str',	\
1274
	ini.get_int, 'ini_get_int'
1275
 
1276
 
1277
section '.data' data readable writable align 16
1278
; uninitialized data
1279
mem.alloc   dd ?
1280
mem.free    dd ?
1281
mem.realloc dd ?
1282
dll.load    dd ?
1283
 
1284
DNSrequestID	dd	?
1285
 
1286
inet_ntoa.buffer	rb	16	; static buffer for inet_ntoa