Subversion Repositories Kolibri OS

Rev

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