Subversion Repositories Kolibri OS

Rev

Rev 1206 | Go to most recent revision | Details | Compare with Previous | Last modification | View Log | RSS feed

Rev Author Line No. Line
1155 clevermous 1
format MS COFF
2
 
3
public @EXPORT as 'EXPORTS'
4
 
1200 hidnplayr 5
include '../struct.inc'
6
include '../proc32.inc'
7
include '../macros.inc'
1155 clevermous 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
1200 hidnplayr 31
	stdcall edx, @IMPORT
1155 clevermous 32
	ret	4
33
 
34
;;===========================================================================;;
35
;; in_addr_t __stdcall inet_addr(__in const char* hostname);                 ;;
1200 hidnplayr 36
inet_addr:								     ;;
1155 clevermous 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.                                        ;;
1200 hidnplayr 127
.get_number:								     ;;
1155 clevermous 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.
1200 hidnplayr 158
	or	al, 20h ; '0'-'9' -> '0'-'9', 'A'-'F' -> 'a'-'f'
1155 clevermous 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);                             ;;
1200 hidnplayr 192
inet_ntoa:								     ;;
1155 clevermous 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	?
1200 hidnplayr 266
	service 	dd	?
1155 clevermous 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);                   ;;
1200 hidnplayr 276
getaddrinfo:								     ;;
1155 clevermous 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);     ;;
1200 hidnplayr 355
getaddrinfo_start:							     ;;
1155 clevermous 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
1200 hidnplayr 432
;       SOCK_STREAM/IPPROTO_TCP, SOCK_DGRAM/IPPROTO_UDP
433
;       (raw sockets are not yet supported by the kernel)
1155 clevermous 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,
1200 hidnplayr 516
;       use localhost for active sockets and INADDR_ANY for passive sockets.
517
	mov	eax, 0x0100007F ; 127.0.0.1 in network byte order
1155 clevermous 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),
1200 hidnplayr 616
;       AA=0 (ignored in requests), TC=0 (no truncation),
617
;       RD=1 (recursion desired)
1155 clevermous 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
1200 hidnplayr 644
	cmp	al, '.' ; end of label?
1155 clevermous 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
1200 hidnplayr 663
	cmp	byte [esi-1], 0 ; that was last label in the name?
1155 clevermous 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:
1200 hidnplayr 672
;       query type = A (host address) = 1,
673
;       query class = IN (internet IPv4 address) = 1
1155 clevermous 674
; Note that network byte order is big-endian.
675
	mov	eax, 0x01000100
676
	stosd
677
; 7. Get DNS server address.
1208 hidnplayr 678
	mcall	75, 0x00000004 ; protocol IP=0, device number=0, function=get DNS address
1197 clevermous 679
	cmp	eax, -1
1208 hidnplayr 680
	je	.ret.dnserr
681
	mov	esi, eax	; put server address to esi
1155 clevermous 682
; 8. Open UDP socket to DNS server, port 53.
1197 clevermous 683
; 8a. Create new socket.
684
	mcall	74, 0, AF_INET, IPPROTO_UDP
1200 hidnplayr 685
	cmp	eax, -1 ; error?
1155 clevermous 686
	jz	.ret.dnserr
1208 hidnplayr 687
	mov	ecx, eax	; put socket handle to ecx
1197 clevermous 688
; 8b. Create sockaddr structure on the stack.
689
	push	0
690
	push	0	; sin_zero
691
	push	esi	; sin_addr
692
	push	AF_INET + (53 shl 24)
693
			; sin_family and sin_port in network byte order
1208 hidnplayr 694
; 8c. Connect.
1197 clevermous 695
	mcall	74, 4, , esp, sizeof.sockaddr_in
696
; 8d. Restore the stack, undo 8b.
697
	add	esp, esi
698
; 8e. Check result.
699
	cmp	eax, -1
700
	jz	.ret.close
1155 clevermous 701
; 9. Send DNS request packet.
702
	sub	edi, esp	; get packet length
1197 clevermous 703
	mov	esi, edi
704
	xor	edi, edi
705
	mcall	74, 6, , esp
1155 clevermous 706
	cmp	eax, -1
707
	jz	.ret.close
708
	mov	eax, [.reqdata]
709
	mov	[eax+__gai_reqdata.socket], ecx
710
	push	-1
711
	pop	eax	; return status: more processing required
712
	jmp	.ret.dns
713
.ret.close:
1197 clevermous 714
	mcall	74, 1
1155 clevermous 715
.ret.dnserr:
716
	push	EAI_AGAIN
717
	pop	eax
718
.ret.dns:
719
; 6. Restore stack pointer and return.
720
	jmp	.ret
721
 
722
;;===========================================================================;;
723
;; int __stdcall getaddrinfo_process(__in struct __gai_reqdata* reqdata,     ;;
724
;;                                   __out struct addrinfo** res);           ;;
1200 hidnplayr 725
getaddrinfo_process:							     ;;
1155 clevermous 726
;;---------------------------------------------------------------------------;;
727
;? Processes network events from DNS reply                                   ;;
728
;;---------------------------------------------------------------------------;;
729
;> first parameter = pointer to struct __gai_reqdata filled by ..._start     ;;
730
;> second parameter = same as for getaddrinfo                                ;;
731
;;---------------------------------------------------------------------------;;
732
;< eax = -1 if more processing required / 0 on success / >0 = error code     ;;
733
;;===========================================================================;;
734
; 0. Create stack frame.
735
	push	ebp
736
	mov	ebp, esp
737
virtual at ebp-.locals_size
738
.locals_start:
739
.datagram	rb	512
740
.addrname	dd	?
741
.name		dd	?
742
.res_list_tail	dd	?
743
.cname		dd	?
744
.recent_restsize dd	?	; this is for memory alloc in ._.generate_data
745
.recent_page	dd	?	; this is for memory alloc in ._.generate_data
746
.locals_size = $ - .locals_start
747
		rd	2
748
.reqdata	dd	?
749
.res		dd	?
750
end virtual
751
	xor	eax, eax
752
	push	eax	; initialize .recent_page
753
	push	eax	; initialize .recent_restsize
754
	push	eax	; initialize .cname
755
	push	[.res]	; initialize .res_list_tail
756
	sub	esp, .locals_size-16	; reserve place for other vars
757
	mov	edx, esp	; edx -> buffer for datagram
758
; 1. Save used registers for __stdcall.
759
	push	ebx esi edi
760
	mov	edi, [.reqdata]
761
; 2. Read UDP datagram.
762
	mov	ecx, [edi+__gai_reqdata.socket]
1197 clevermous 763
	push	edi
1208 hidnplayr 764
	mcall	74, 7, , , 512, 0
1197 clevermous 765
	pop	edi
1155 clevermous 766
; 3. Ignore events for other sockets (return if no data read)
767
	test	eax, eax
768
	jz	.ret.more_processing_required
769
; 4. Sanity check: discard too short packets.
770
	xchg	ecx, eax	; save packet length in ecx
771
	cmp	ecx, 12
772
	jb	.ret.more_processing_required
773
; 5. Discard packets with ID != request ID.
774
	mov	eax, dword [edi+__gai_reqdata.reqid]
775
	cmp	ax, [edx]
776
	jnz	.ret.more_processing_required
777
; 6. Sanity check: discard query packets.
778
	test	byte [edx+2], 80h
779
	jz	.ret.more_processing_required
780
; 7. Sanity check: must be exactly one query (our).
781
	cmp	word [edx+4], 0x0100	; note network byte order
782
	jnz	.ret.more_processing_required
783
; 8. Check for errors. Return EAI_NONAME for error code 3 and EAI_FAIL for other.
784
	mov	al, [edx+3]
785
	and	al, 0xF
786
	jz	@f
787
	cmp	al, 3
788
	jnz	.ret.no_recovery
789
	jmp	.ret.no_name
790
@@:
791
; 9. Locate answers section. Exactly 1 query is present in this packet.
792
	add	ecx, edx	; ecx = limit
793
	lea	esi, [edx+12]
794
	call	.skip_name
795
	lodsd		; skip QTYPE and QCLASS field
796
	cmp	esi, ecx
797
	ja	.ret.no_recovery
798
; 10. Loop through all answers.
799
	movzx	ebx, word [edx+6]	; get answers count
800
	xchg	bl, bh		; network -> Intel byte order
801
.answers_loop:
802
	dec	ebx
803
	js	.answers_done
804
; 10a. Process each record.
805
	mov	[.name], esi
806
; 10b. Skip name field.
807
	call	.skip_name
808
; 10c. Get record information, handle two types for class IN (internet).
809
	lodsd		; get type and class
810
	cmp	esi, ecx
811
	ja	.ret.no_recovery
1200 hidnplayr 812
	cmp	eax, 0x01000500 ; type=5, class=1?
1155 clevermous 813
	jz	.got_cname
1200 hidnplayr 814
	cmp	eax, 0x01000100 ; type=1, class=1?
1155 clevermous 815
	jnz	.answers_loop.next
816
.got_addr:
817
; 10d. Process record A, host address.
818
	add	esi, 10
819
	cmp	esi, ecx
820
	ja	.ret.no_recovery
821
	cmp	word [esi-6], 0x0400	; RDATA for A records must be 4 bytes long
822
	jnz	.ret.no_recovery
823
	mov	eax, [.name]
824
	mov	[.addrname], eax
825
; 10e. Create corresponding record in the answer.
826
	push	ebx ecx esi
827
	mov	eax, [esi-4]	; IP address
828
	mov	esi, [.res_list_tail]	; pointer to result
829
	test	esi, esi
830
	jz	.no_result	; do not save if .res is NULL
1200 hidnplayr 831
	mov	ebx, [.reqdata] ; request data
1155 clevermous 832
	call	getaddrinfo._.generate_data
833
	mov	[.res_list_tail], esi
834
	pop	esi ecx ebx
835
	cmp	[.res_list_tail], 0
836
	jnz	.answers_loop
837
; 10f. If generate_data failed (this means memory allocation failure), abort
838
	jmp	.ret.no_memory
839
.no_result:
840
	pop	esi ecx ebx
841
	jmp	.answers_loop
842
.got_cname:
843
; 10g. Process record CNAME, main host name.
844
	lea	eax, [esi+6]
845
	mov	[.cname], eax
846
.answers_loop.next:
847
; 10h. Skip other record fields, advance to next record.
848
	lodsd	; skip TTL
849
	xor	eax, eax
850
	lodsw	; get length of RDATA field
851
	xchg	al, ah	; network -> Intel byte order
852
	add	esi, eax
853
	cmp	esi, ecx
854
	ja	.ret.no_recovery
855
	jmp	.answers_loop
856
.answers_done:
857
; 11. Check that there is at least 1 answer.
858
	mov	eax, [.res_list_tail]
859
	cmp	[.res], eax
860
	jz	.ret.no_data
861
; 12. If canonical name was required, add it now.
862
	mov	eax, [.reqdata]
863
	test	byte [eax+__gai_reqdata.flags], AI_CANONNAME
864
	jz	.no_canon_name
865
; 12a. If at least one CNAME record is present, use name from last such record.
866
; Otherwise, use name from one of A records.
867
	mov	esi, [.cname]
868
	test	esi, esi
869
	jnz	.has_cname
870
	mov	esi, [.addrname]
871
.has_cname:
872
; 12b. Calculate name length.
873
	call	.get_name_length
874
	jc	.ret.no_recovery
875
; 12c. Check that the caller really want to get data.
876
	cmp	[.res], 0
877
	jz	.no_canon_name
878
; 12d. Allocate memory for name.
879
	call	getaddrinfo._.memalloc
880
	test	edi, edi
881
	jz	.ret.no_memory
882
; 12e. Make first entry in .res list point to canonical name.
883
	mov	eax, [.res]
884
	mov	eax, [eax]
885
	mov	[eax+addrinfo.ai_canonname], edi
886
; 12f. Decode name.
887
	call	.decode_name
888
.no_canon_name:
889
; 13. Set status to success.
890
	xor	eax, eax
891
	jmp	.ret.close
892
; Handle errors.
893
.ret.more_processing_required:
894
	push	-1
895
	pop	eax
896
	jmp	.ret
897
.ret.no_recovery:
898
	push	EAI_FAIL
899
	pop	eax
900
	jmp	.ret.destroy
901
.ret.no_memory:
902
	push	EAI_MEMORY
903
	pop	eax
904
	jmp	.ret.destroy
905
.ret.no_name:
906
.ret.no_data:
907
	push	EAI_NONAME
908
	pop	eax
909
.ret.destroy:
910
; 14. If an error occured, free memory acquired so far.
911
	push	eax
912
	mov	esi, [.res]
913
	test	esi, esi
914
	jz	@f
915
	pushd	[esi]
916
	call	freeaddrinfo
917
	and	dword [esi], 0
918
@@:
919
	pop	eax
920
.ret.close:
921
; 15. Close socket.
922
	push	eax
923
	mov	ecx, [.reqdata]
924
	mov	ecx, [ecx+__gai_reqdata.socket]
1197 clevermous 925
	mcall	74, 1
1155 clevermous 926
	pop	eax
927
; 16. Restore used registers, destroy stack frame and return.
928
.ret:
929
	pop	edi esi ebx
930
	mov	esp, ebp
931
	pop	ebp
932
	ret	8
933
 
934
;;===========================================================================;;
935
;; Internal auxiliary function for skipping names in DNS packet.             ;;
1200 hidnplayr 936
.skip_name:								     ;;
1155 clevermous 937
;;---------------------------------------------------------------------------;;
938
;? Skips name in DNS packet.                                                 ;;
939
;;---------------------------------------------------------------------------;;
940
;> esi -> name                                                               ;;
941
;> ecx = end of packet                                                       ;;
942
;;---------------------------------------------------------------------------;;
943
;< esi -> end of name                                                        ;;
944
;;===========================================================================;;
945
	xor	eax, eax
946
	cmp	esi, ecx
947
	jae	.skip_name.done
948
	lodsb
949
	test	al, al
950
	jz	.skip_name.done
951
	test	al, 0xC0
952
	jnz	.skip_name.pointer
953
	add	esi, eax
954
	jmp	.skip_name
955
.skip_name.pointer:
956
	inc	esi
957
.skip_name.done:
958
	ret
959
 
960
;;===========================================================================;;
961
;; Internal auxiliary function for calculating length of name in DNS packet. ;;
1200 hidnplayr 962
.get_name_length:							     ;;
1155 clevermous 963
;;---------------------------------------------------------------------------;;
964
;? Calculate length of name (including terminating zero) in DNS packet.      ;;
965
;;---------------------------------------------------------------------------;;
966
;> edx = start of packet                                                     ;;
967
;> esi -> name                                                               ;;
968
;> ecx = end of packet                                                       ;;
969
;;---------------------------------------------------------------------------;;
970
;< eax = length of name                                                      ;;
971
;< CF set on error / cleared on success                                      ;;
972
;;===========================================================================;;
973
	xor	ebx, ebx	; ebx will hold data length
974
.get_name_length.zero:
975
	xor	eax, eax
976
.get_name_length.loop:
977
	cmp	esi, ecx
978
	jae	.get_name_length.fail
979
	lodsb
980
	test	al, al
981
	jz	.get_name_length.done
982
	test	al, 0xC0
983
	jnz	.get_name_length.pointer
984
	add	esi, eax
985
	inc	ebx
986
	add	ebx, eax
987
	cmp	ebx, 256
988
	jbe	.get_name_length.loop
989
.get_name_length.fail:
990
	stc
991
	ret
992
.get_name_length.pointer:
993
	and	al, 0x3F
994
	mov	ah, al
995
	lodsb
996
	lea	esi, [edx+eax]
997
	jmp	.get_name_length.zero
998
.get_name_length.done:
999
	test	ebx, ebx
1000
	jz	.get_name_length.fail
1001
	xchg	eax, ebx
1002
	clc
1003
	ret
1004
 
1005
;;===========================================================================;;
1006
;; Internal auxiliary function for decoding DNS name.                        ;;
1200 hidnplayr 1007
.decode_name:								     ;;
1155 clevermous 1008
;;---------------------------------------------------------------------------;;
1009
;? Decode name in DNS packet.                                                ;;
1010
;;---------------------------------------------------------------------------;;
1011
;> edx = start of packet                                                     ;;
1012
;> esi -> name in packet                                                     ;;
1013
;> edi -> buffer for decoded name                                            ;;
1014
;;===========================================================================;;
1015
	xor	eax, eax
1016
	lodsb
1017
	test	al, al
1018
	jz	.decode_name.done
1019
	test	al, 0xC0
1020
	jnz	.decode_name.pointer
1021
	mov	ecx, eax
1022
	rep	movsb
1023
	mov	al, '.'
1024
	stosb
1025
	jmp	.decode_name
1026
.decode_name.pointer:
1027
	and	al, 0x3F
1028
	mov	ah, al
1029
	lodsb
1030
	lea	esi, [edx+eax]
1031
	jmp	.decode_name
1032
.decode_name.done:
1033
	mov	byte [edi-1], 0
1034
	ret
1035
 
1036
;;===========================================================================;;
1037
;; Internal auxiliary function for allocating memory for getaddrinfo.        ;;
1200 hidnplayr 1038
getaddrinfo._.memalloc: 						     ;;
1155 clevermous 1039
;;---------------------------------------------------------------------------;;
1040
;? Memory allocation.                                                        ;;
1041
;;---------------------------------------------------------------------------;;
1042
;> eax = size in bytes, must be less than page size.                         ;;
1043
;> [ebp-4] = .recent_page = last allocated page                              ;;
1044
;> [ebp-8] = .recent_restsize = bytes rest in last allocated page            ;;
1045
;;---------------------------------------------------------------------------;;
1046
;< edi -> allocated memory / NULL on error                                   ;;
1047
;;===========================================================================;;
1048
; 1. Set edi to result of function.
1049
	mov	edi, [ebp-4]
1050
; 2. Check whether we need to allocate a new page.
1051
	cmp	eax, [ebp-8]
1052
	jbe	.no_new_page
1053
; 2. Allocate new page if need. Reset edi to new result.
1054
	push	eax ebx
1055
	mcall	68, 12, 0x1000
1056
	xchg	edi, eax	; put result to edi
1057
	pop	ebx eax
1058
; 3. Check returned value of allocator. Fail if it failed.
1059
	test	edi, edi
1060
	jz	.ret
1061
; 4. Update .recent_page and .recent_restsize.
1062
	add	edi, 4
1063
	sub	ecx, 4
1064
	mov	[ebp-4], edi
1065
	mov	[ebp-8], ecx
1066
.no_new_page:
1067
; 5. Increase number of objects on this page.
1068
	push	eax
1069
	mov	eax, edi
1070
	and	eax, not 0xFFF
1071
	inc	dword [eax]
1072
	pop	eax
1073
; 6. Advance last allocated pointer, decrease memory size.
1074
	add	[ebp-4], eax
1075
	sub	[ebp-8], eax
1076
; 7. Return.
1077
.ret:
1078
	ret
1079
 
1080
;;===========================================================================;;
1081
;; Internal auxiliary function for freeing memory for freeaddrinfo.          ;;
1200 hidnplayr 1082
getaddrinfo._.memfree:							     ;;
1155 clevermous 1083
;;---------------------------------------------------------------------------;;
1084
;? Free memory.                                                              ;;
1085
;;---------------------------------------------------------------------------;;
1086
;> eax = pointer                                                             ;;
1087
;;===========================================================================;;
1088
; 1. Get start of page.
1089
	mov	ecx, eax
1090
	and	ecx, not 0xFFF
1091
; 2. Decrease number of objects.
1092
	dec	dword [ecx]
1093
; 3. If it goes to zero, free the page.
1094
	jnz	@f
1095
	push	ebx
1096
	mcall	68, 13
1097
	pop	ebx
1098
@@:
1099
; 4. Done.
1100
	ret
1101
 
1102
;;===========================================================================;;
1200 hidnplayr 1103
getaddrinfo._.generate_data:						     ;;
1155 clevermous 1104
;;---------------------------------------------------------------------------;;
1105
;? Generate item(s) of getaddrinfo result list by one IP address.            ;;
1106
;;---------------------------------------------------------------------------;;
1107
;> eax = IP address                                                          ;;
1108
;> ebx = request data                                                        ;;
1109
;> esi = pointer to result                                                   ;;
1110
;> [ebp-4] = .recent_page = last allocated page                              ;;
1111
;> [ebp-8] = .recent_restsize = bytes rest in last allocated page            ;;
1112
;;---------------------------------------------------------------------------;;
1113
;< esi = pointer to next list item for result / NULL on error                ;;
1114
;;===========================================================================;;
1115
; 1. If no service is given, append one item with zero port.
1116
; append one item with zero socktype/protocol/port.
1117
	cmp	[ebx+__gai_reqdata.service], -1
1118
	jnz	.has_service
1119
	call	.append_item
1120
; 1a. If neither protocol nor socktype were specified,
1200 hidnplayr 1121
;       leave zeroes in socktype and protocol.
1155 clevermous 1122
	mov	cl, [ebx+__gai_reqdata.socktype]
1123
	test	cl, cl
1124
	jz	.no_socktype
1125
; 1b. Otherwise, set socktype and protocol to desired.
1126
	call	.set_socktype
1127
.no_socktype:
1128
	ret
1129
.has_service:
1130
; 2. If TCP is allowed, append item for TCP.
1131
	cmp	[ebx+__gai_reqdata.socktype], 0
1132
	jz	.tcp_ok
1133
	cmp	[ebx+__gai_reqdata.socktype], SOCK_STREAM
1134
	jnz	.tcp_disallowed
1135
.tcp_ok:
1136
	call	.append_item
1137
	mov	cl, SOCK_STREAM
1138
	call	.set_socktype
1139
	call	.set_port
1140
.tcp_disallowed:
1141
; 3. If UDP is allowed, append item for UDP.
1142
	cmp	[ebx+__gai_reqdata.socktype], 0
1143
	jz	.udp_ok
1144
	cmp	[ebx+__gai_reqdata.socktype], SOCK_DGRAM
1145
	jnz	.udp_disallowed
1146
.udp_ok:
1147
	call	.append_item
1148
	mov	cl, SOCK_DGRAM
1149
	call	.set_socktype
1150
	call	.set_port
1151
.udp_disallowed:
1152
	ret
1153
 
1154
.append_item:
1155
; 1. Allocate memory for struct sockaddr_in and struct addrinfo.
1156
	push	eax
1157
	push	sizeof.addrinfo + sizeof.sockaddr_in
1158
	pop	eax
1159
	call	getaddrinfo._.memalloc
1160
; 2. Check for memory allocation fail.
1161
	test	edi, edi
1162
	jz	.no_memory
1163
; 3. Zero allocated memory.
1164
	push	(sizeof.addrinfo + sizeof.sockaddr_in) / 4
1165
	pop	ecx
1166
	xor	eax, eax
1167
	push	edi
1168
	rep	stosd
1169
	pop	edi
1170
; 4. Fill struct addrinfo.
1171
	mov	eax, [ebx+__gai_reqdata.flags]
1172
	mov	[edi+addrinfo.ai_flags], eax
1173
	mov	byte [edi+addrinfo.ai_family], PF_INET
1174
	mov	byte [edi+addrinfo.ai_addrlen], sizeof.sockaddr_in
1175
	lea	ecx, [edi+sizeof.addrinfo]
1176
	mov	[edi+addrinfo.ai_addr], ecx
1177
; 5. Fill struct sockaddr_in.
1178
	mov	byte [ecx+sockaddr_in.sin_family], PF_INET
1179
	pop	eax
1180
	mov	[ecx+sockaddr_in.sin_addr], eax
1181
; 6. Append new item to the list.
1182
	mov	[esi], edi
1183
	lea	esi, [edi+addrinfo.ai_next]
1184
; 7. Return.
1185
	ret
1186
.no_memory:
1187
	pop	eax
1188
	xor	esi, esi
1189
	ret
1190
 
1191
.set_socktype:
1192
; Set ai_socktype and ai_protocol fields by given socket type.
1193
	mov	byte [edi+addrinfo.ai_socktype], cl
1194
	dec	cl
1195
	jnz	.set_udp
1196
.set_tcp:
1197
	mov	byte [edi+addrinfo.ai_protocol], IPPROTO_TCP
1198
	ret
1199
.set_udp:
1200
	mov	byte [edi+addrinfo.ai_protocol], IPPROTO_UDP
1201
	ret
1202
 
1203
.set_port:
1204
; Just copy port from input __gai_reqdata to output addrinfo.
1205
	push	edx
1206
	mov	edx, [ebx+__gai_reqdata.service]
1207
	xchg	dl, dh	; convert to network byte order
1208
	mov	[edi+sizeof.addrinfo+sockaddr_in.sin_port], dx
1209
	pop	edx
1210
	ret
1211
 
1212
;;===========================================================================;;
1213
;; void __stdcall getaddrinfo_abort(__in struct __gai_reqdata* reqdata);      ;;
1200 hidnplayr 1214
getaddrinfo_abort:							     ;;
1155 clevermous 1215
;;---------------------------------------------------------------------------;;
1216
;? Abort process started by getaddrinfo_start, free all resources.           ;;
1217
;;---------------------------------------------------------------------------;;
1218
;> first parameter = pointer to struct __gai_reqdata filled by ..._start     ;;
1219
;;===========================================================================;;
1220
; 0. Save used registers for __stdcall.
1221
	push	ebx
1222
; 1. Allocated resources: only socket, so close it and return.
1223
	mov	eax, [esp+8]
1224
	mov	ecx, [eax+__gai_reqdata.socket]
1197 clevermous 1225
	mcall	74, 1
1155 clevermous 1226
; 2. Restore used registers and return.
1227
	pop	ebx
1228
	ret	4
1229
 
1230
;;===========================================================================;;
1231
;; void __stdcall freeaddrinfo(__in struct addrinfo* ai);                    ;;
1200 hidnplayr 1232
freeaddrinfo:								     ;;
1155 clevermous 1233
;;---------------------------------------------------------------------------;;
1234
;? Free one or more addrinfo structures returned by getaddrinfo.             ;;
1235
;;---------------------------------------------------------------------------;;
1236
;> first parameter = head of list of structures                              ;;
1237
;                    (may be arbitrary sublist of original)                  ;;
1238
;;===========================================================================;;
1239
; 1. Loop for all items in the list.
1240
	mov	edx, [esp+4]	; eax = ai
1241
.loop:
1242
	test	edx, edx
1243
	jz	.done
1244
; 2. Free each item.
1245
; 2a. Free ai_canonname, if allocated.
1246
	mov	eax, [edx+addrinfo.ai_canonname]
1247
	test	eax, eax
1248
	jz	.no_canon_name
1249
	call	getaddrinfo._.memfree
1250
.no_canon_name:
1251
; 2b. Remember next item
1200 hidnplayr 1252
;       (after freeing the field ai_next can became unavailable).
1155 clevermous 1253
	pushd	[edx+addrinfo.ai_next]
1254
; 2c. Free item itself.
1255
	xchg	eax, edx
1256
	call	getaddrinfo._.memfree
1257
; 2d. Restore pointer to next item and continue loop.
1258
	pop	edx
1259
	jmp	.loop
1260
.done:
1261
; 3. Done.
1262
	ret	4
1263
 
1264
;;===========================================================================;;
1265
;;///////////////////////////////////////////////////////////////////////////;;
1266
;;===========================================================================;;
1267
;! Exported functions section                                                ;;
1268
;;===========================================================================;;
1269
;;///////////////////////////////////////////////////////////////////////////;;
1270
;;===========================================================================;;
1271
 
1272
 
1273
align 4
1274
@EXPORT:
1275
export	\
1276
	lib_init		, 'lib_init'		, \
1277
	0x00010001		, 'version'		, \
1278
	inet_addr		, 'inet_addr'		, \
1279
	inet_ntoa		, 'inet_ntoa'		, \
1200 hidnplayr 1280
	getaddrinfo		, 'getaddrinfo' 	, \
1155 clevermous 1281
	getaddrinfo_start	, 'getaddrinfo_start'	, \
1200 hidnplayr 1282
	getaddrinfo_process	, 'getaddrinfo_process' , \
1155 clevermous 1283
	getaddrinfo_abort	, 'getaddrinfo_abort'	, \
1284
	freeaddrinfo		, 'freeaddrinfo'
1285
 
1286
; import from libini
1287
align 4
1288
@IMPORT:
1289
 
1200 hidnplayr 1290
library libini, 'libini.obj'
1155 clevermous 1291
import	libini, \
1292
	ini.get_str, 'ini_get_str',	\
1293
	ini.get_int, 'ini_get_int'
1294
 
1295
 
1296
section '.data' data readable writable align 16
1297
; uninitialized data
1298
mem.alloc   dd ?
1299
mem.free    dd ?
1300
mem.realloc dd ?
1301
dll.load    dd ?
1302
 
1303
DNSrequestID	dd	?
1304
 
1305
inet_ntoa.buffer	rb	16	; static buffer for inet_ntoa