Subversion Repositories Kolibri OS

Rev

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