Subversion Repositories Kolibri OS

Rev

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

Rev Author Line No. Line
431 serge 1
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
2
;;                                                              ;;
3
;; Copyright (C) KolibriOS team 2004-2007. All rights reserved. ;;
4
;; Distributed under terms of the GNU General Public License    ;;
5
;;                                                              ;;
6
;;  SOCKET.INC                                                  ;;
7
;;                                                              ;;
8
;;  Sockets constants, structures and functions                 ;;
9
;;                                                              ;;
10
;;  Last revision: 11.11.2006                                   ;;
11
;;                                                              ;;
12
;;  This file contains the following:                           ;;
13
;;    is_localport_unused                                       ;;
14
;;    get_free_socket                                           ;;
15
;;    socket_open                                               ;;
16
;;    socket_open_tcp                                           ;;
17
;;    socket_close                                              ;;
18
;;    socket_close_tcp                                          ;;
19
;;    socket_poll                                               ;;
20
;;    socket_status                                             ;;
21
;;    socket_read                                               ;;
22
;;    socket_write                                              ;;
23
;;    socket_write_tcp                                          ;;
24
;;                                                              ;;
25
;;                                                              ;;
26
;;  Changes history:                                            ;;
27
;;   22.09.2003 - [Mike Hibbett] : mikeh@oceanfree.net          ;;
28
;;   11.11.2006 - [Johnny_B] and [smb]                          ;;
29
;;                                                              ;;
30
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
261 hidnplayr 31
 
593 mikedld 32
$Revision: 915 $
33
 
34
 
261 hidnplayr 35
;
36
;  Socket Descriptor + Buffer
37
;
38
;    0                   1                   2                   3
39
;    0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
40
;
41
;   +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
42
;  0|                    Status ( of this buffer )                  |
43
;   +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
44
;  4|  Application Process ID                                       |
45
;   +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
46
;  8|                  Local IP Address                             |
47
;   +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
48
; 12| Local IP Port                 | Unused ( set to 0 )           |
49
;   +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
50
; 16|                  Remote IP Address                            |
51
;   +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
52
; 20| Remote IP Port                | Unused ( set to 0 )           |
53
;   +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
54
; 24|   Rx Data Count                                   INTEL format|
55
;   +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
56
; 28|                 TCB STATE                         INTEL format|
57
;   +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
58
; 32|   TCB Timer (seconds)                             INTEL format|
59
;   +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
60
; 36| ISS (Inital Sequence # used by this connection )   INET format|
61
;   +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
62
; 40| IRS ( Inital Receive Sequence # )                  INET format|
63
;   +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
64
; 44| SND.UNA  Seq # of unack'ed sent packets            INET format|
65
;   +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
66
; 48| SND.NXT  Next send seq # to use                    INET format|
67
;   +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
68
; 52| SND.WND  Send window                               INET format|
69
;   +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
70
; 56| RCV.NXT  Next expected receive sequence #          INET format|
71
;   +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
72
; 60| RCV.WND  Receive window                            INET format|
73
;   +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
74
; 64| SEG.LEN  Segment length                           INTEL format|
75
;   +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
76
; 68| SEG.WND  Segment window                           INTEL format|
77
;   +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
78
; 72| Retransmit queue # NOW WINDOW SIZE TIMER          INTEL format|
79
;   +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
907 mikedld 80
; 76|       RX Data Buffer                                          |
261 hidnplayr 81
;   +-+-+-..........                                               -+
82
 
83
 
84
; so, define struct
85
struc SOCKET
907 mikedld 86
{
909 mikedld 87
   .PrevPtr		    dd	 ?
88
   .NextPtr		    dd	 ?
907 mikedld 89
   .Status		    dd	 ?  ;+00 - Status ( of this buffer )
379 serge 90
   .PID 		    dd	 ?  ;+04 - Application Process ID
907 mikedld 91
   .LocalIP		    dd	 ?  ;+08 - Local IP Address
323 hidnplayr 92
   .LocalPort		    dw	 ?  ;+12 - Local Port
93
   .RemoteIP		    dd	 ?  ;+16 - Remote IP Address
94
   .RemotePort		    dw	 ?  ;+20 - Remote Port
907 mikedld 95
   .OrigRemoteIP	    dd	 ?
96
   .OrigRemotePort	    dw	 ?
323 hidnplayr 97
   .rxDataCount 	    dd	 ?  ;+24 - Rx Data Count
98
   .TCBState		    dd	 ?  ;+28 - TCB STATE
379 serge 99
   .TCBTimer		    dd	 ?  ;+32 - TCB Timer (seconds)
323 hidnplayr 100
   .ISS 		    dd	 ?  ;+36 - Initial Send Sequence
101
   .IRS 		    dd	 ?  ;+40 - Initial Receive Sequence
102
   .SND_UNA		    dd	 ?  ;+44 - Sequence number of unack'ed sent packets
379 serge 103
   .SND_NXT		    dd	 ?  ;+48 - Next send sequence number to use
323 hidnplayr 104
   .SND_WND		    dd	 ?  ;+52 - Send window
105
   .RCV_NXT		    dd	 ?  ;+56 - Next receive sequence number to use
106
   .RCV_WND		    dd	 ?  ;+60 - Receive window
107
   .SEG_LEN		    dd	 ?  ;+64 - Segment length
108
   .SEG_WND		    dd	 ?  ;+68 - Segment window
379 serge 109
   .wndsizeTimer	    dd	 ?  ;+72 - Retransmit queue # NOW WINDOW SIZE TIMER
323 hidnplayr 110
   .rxData		    dd	 ?  ;+76 - receive data buffer here
261 hidnplayr 111
}
112
 
113
virtual at 0
114
  SOCKET SOCKET
115
end virtual
116
 
379 serge 117
; simple macro calcing real memory address of SOCKET struct by socket's
907 mikedld 118
;macro   Index2RealAddr reg
119
;{
120
;        shl     reg, 12
121
;    add     reg, sockets
122
;}
261 hidnplayr 123
 
124
;Constants
125
; current socket statuses
907 mikedld 126
SOCK_EMPTY	   =	 0	  ; socket not in use
127
SOCK_OPEN	   =	 1	  ; open issued, but no data sent
261 hidnplayr 128
 
129
; TCP opening modes
323 hidnplayr 130
SOCKET_PASSIVE	   equ	   0
131
SOCKET_ACTIVE	   equ	   1
261 hidnplayr 132
 
907 mikedld 133
proc net_socket_alloc stdcall uses ebx ecx edx edi
134
	stdcall kernel_alloc, SOCKETBUFFSIZE
135
	DEBUGF	1, "K : net_socket_alloc (0x%x)\n", eax
136
	or	eax, eax
137
	jz	.exit
138
 
139
	push	eax
140
	mov	edi, eax
141
	mov	ecx, SOCKETBUFFSIZE / 4
142
	cld
143
	xor	eax, eax
144
	rep	stosd
145
	pop	eax
146
 
147
	mov	ebx, net_sockets
148
	push	[ebx + SOCKET.NextPtr]
149
	mov	[ebx + SOCKET.NextPtr], eax
150
	mov	[eax + SOCKET.PrevPtr], ebx
151
	pop	ebx
152
	mov	[eax + SOCKET.NextPtr], ebx
153
	or	ebx, ebx
154
	jz	@f
155
	mov	[ebx + SOCKET.PrevPtr], eax
156
 
157
    @@: mov	ebx, [TASK_BASE]
158
	mov	ebx, [ebx + TASKDATA.pid]
159
	mov	[eax + SOCKET.PID], ebx
160
 
161
  .exit:
162
	ret
163
endp
164
 
165
proc net_socket_free stdcall uses ebx ecx edx, sock:DWORD
166
	mov	eax, [sock]
167
	DEBUGF	1, "K : net_socket_free (0x%x)\n", eax
168
	or	eax, eax
169
	jz	.error
170
 
171
	mov	ebx, net_sockets
172
	mov	ecx, [TASK_BASE]
173
	mov	ecx, [ecx + TASKDATA.pid]
174
  .next_socket:
175
	mov	ebx, [ebx + SOCKET.NextPtr]
176
	or	ebx, ebx
177
	jz	.error
178
	cmp	ebx, eax
179
	jne	.next_socket
180
	;cmp     [ebx + SOCKET.PID], ecx
181
	;jne     .next_socket
182
 
183
	mov	ebx, [eax + SOCKET.NextPtr]
184
	mov	eax, [eax + SOCKET.PrevPtr]
185
	mov	[eax + SOCKET.NextPtr], ebx
186
	or	ebx, ebx
187
	jz	@f
188
	mov	[ebx + SOCKET.PrevPtr], eax
189
 
190
    @@: stdcall kernel_free, [sock]
191
	ret
192
 
193
  .error:
194
	DEBUGF	1, "K :   failed\n"
195
	ret
196
endp
197
 
198
proc net_socket_num_to_addr stdcall uses ebx ecx, x:DWORD
199
; FIXME: do real transform
200
	mov	eax, [x]
201
	mov	ebx, net_sockets
202
	mov	ecx, [TASK_BASE]
203
	mov	ecx, [ecx + TASKDATA.pid]
204
  .next_socket:
205
	mov	ebx, [ebx + SOCKET.NextPtr]
206
	or	ebx, ebx
207
	jz	.error
208
	cmp	ebx, eax
209
	jne	.next_socket
210
	;cmp     [ebx + SOCKET.PID], ecx
211
	;jne     .next_socket
212
	ret
213
 
214
  .error:
215
	xor	eax, eax
216
	ret
217
endp
218
 
219
proc net_socket_addr_to_num stdcall uses ebx ecx, x:DWORD
220
; FIXME: do real transform
221
	mov	eax, [x]
222
	mov	ebx, net_sockets
223
	mov	ecx, [TASK_BASE]
224
	mov	ecx, [ecx + TASKDATA.pid]
225
  .next_socket:
226
	mov	ebx, [ebx + SOCKET.NextPtr]
227
	or	ebx, ebx
228
	jz	.error
229
	cmp	ebx, eax
230
	jne	.next_socket
231
	;cmp     [ebx + SOCKET.PID], ecx
232
	;jne     .next_socket
233
	ret
234
 
235
  .error:
236
	xor	eax, eax
237
	ret
238
endp
239
 
261 hidnplayr 240
;***************************************************************************
241
;   Function
242
;      is_localport_unused
243
;
244
;   Description
245
;         scans through all the active sockets , looking to see if the
246
;      port number specified in bx is in use as a localport number.
247
;      This is useful when you want a to generate a unique local port
248
;      number.
249
;          On return, eax = 1 for free, 0 for in use
250
;
251
;***************************************************************************
907 mikedld 252
proc is_localport_unused stdcall
261 hidnplayr 253
 
907 mikedld 254
	xchg	bl, bh
261 hidnplayr 255
 
907 mikedld 256
	xor	eax, eax			; Assume the return value is 'free'
257
	inc	al
258
	mov	edx, net_sockets
261 hidnplayr 259
 
907 mikedld 260
  .next_socket:
261
	mov	edx, [edx + SOCKET.NextPtr]
262
	or	edx, edx
263
	jz	.exit
264
	cmp	[edx + SOCKET.LocalPort], bx
265
	jne	.next_socket			; Return back if the port is not occupied
261 hidnplayr 266
 
907 mikedld 267
	dec	al				; return 'in use'
261 hidnplayr 268
 
907 mikedld 269
  .exit:
270
	ret
271
endp
261 hidnplayr 272
 
273
 
274
;***************************************************************************
275
;   Function
276
;      socket_open
277
;
278
;   Description
279
;       find a free socket
280
;       local port in ebx
281
;       remote port in ecx
282
;       remote ip in edx
283
;       return socket # in eax, -1 if none available
284
;
285
;***************************************************************************
907 mikedld 286
proc socket_open stdcall
287
	call	net_socket_alloc
288
	or	eax, eax
289
	jz	.error
261 hidnplayr 290
 
907 mikedld 291
	DEBUGF	1, "K : socket_open (0x%x)\n", eax
261 hidnplayr 292
 
907 mikedld 293
	push	eax
261 hidnplayr 294
 
907 mikedld 295
	mov	[eax + SOCKET.Status], SOCK_OPEN
296
	xchg	bh, bl
297
	mov	[eax + SOCKET.LocalPort], bx
298
	xchg	ch, cl
299
	mov	[eax + SOCKET.RemotePort], cx
300
	mov	ebx, [stack_ip]
301
	mov	[eax + SOCKET.LocalIP], ebx
302
	mov	[eax + SOCKET.RemoteIP], edx
261 hidnplayr 303
 
907 mikedld 304
	;pop     eax      ; Get the socket number back, so we can return it
305
	stdcall net_socket_addr_to_num
306
	ret
261 hidnplayr 307
 
907 mikedld 308
  .error:
309
	DEBUGF	1, "K : socket_open (fail)\n"
310
	or	eax, -1
311
	ret
312
endp
261 hidnplayr 313
 
314
 
315
;***************************************************************************
316
;   Function
317
;      socket_open_tcp
318
;
319
;   Description
320
;       Opens a TCP socket in PASSIVE or ACTIVE mode
321
;       find a free socket
322
;       local port in ebx ( intel format )
323
;       remote port in ecx ( intel format )
324
;       remote ip in edx ( in Internet byte order )
325
;       Socket open mode in esi  ( SOCKET_PASSIVE or SOCKET_ACTIVE )
326
;       return socket # in eax, -1 if none available
327
;
328
;***************************************************************************
907 mikedld 329
proc socket_open_tcp stdcall
330
local sockAddr dd ?
261 hidnplayr 331
 
907 mikedld 332
	cmp	esi, SOCKET_PASSIVE
333
	jne	.skip_port_check
261 hidnplayr 334
 
907 mikedld 335
	push	ebx
336
	mov	eax, ebx
337
	xchg	al, ah
338
	mov	ebx, net_sockets
261 hidnplayr 339
 
907 mikedld 340
  .next_socket:
341
	mov	ebx, [ebx + SOCKET.NextPtr]
342
	or	ebx, ebx
343
	jz	.last_socket
344
	cmp	[ebx + SOCKET.TCBState], TCB_LISTEN
345
	jne	.next_socket
346
	cmp	[ebx + SOCKET.LocalPort], ax
347
	jne	.next_socket
261 hidnplayr 348
 
907 mikedld 349
	xchg	al, ah
350
	DEBUGF	1, "K : error: port %u is listened by 0x%x\n", ax, ebx
351
	pop	ebx
352
	jmp	.error
261 hidnplayr 353
 
907 mikedld 354
  .last_socket:
355
	pop	ebx
261 hidnplayr 356
 
907 mikedld 357
  .skip_port_check:
358
	call	net_socket_alloc
359
	or	eax, eax
360
	jz	.error
261 hidnplayr 361
 
907 mikedld 362
	DEBUGF	1, "K : socket_open_tcp (0x%x)\n", eax
261 hidnplayr 363
 
907 mikedld 364
	mov	[sockAddr], eax
261 hidnplayr 365
 
907 mikedld 366
	; TODO - check this works!
367
	;xxx: already 0 (intialized by net_socket_alloc)
368
	;mov     [eax + SOCKET.wndsizeTimer], 0     ; Reset the window timer.
261 hidnplayr 369
 
907 mikedld 370
	xchg	bh, bl
371
	mov	[eax + SOCKET.LocalPort], bx
372
	xchg	ch, cl
373
	mov	[eax + SOCKET.RemotePort], cx
374
	mov	[eax + SOCKET.OrigRemotePort], cx
375
	mov	ebx, [stack_ip]
376
	mov	[eax + SOCKET.LocalIP], ebx
377
	mov	[eax + SOCKET.RemoteIP], edx
378
	mov	[eax + SOCKET.OrigRemoteIP], edx
261 hidnplayr 379
 
907 mikedld 380
	mov	ebx, TCB_LISTEN
381
	cmp	esi, SOCKET_PASSIVE
382
	je	@f
383
	mov	ebx, TCB_SYN_SENT
384
    @@: mov	[eax + SOCKET.TCBState], ebx		; Indicate the state of the TCB
261 hidnplayr 385
 
907 mikedld 386
	cmp	ebx, TCB_LISTEN
387
	je	.exit
261 hidnplayr 388
 
907 mikedld 389
	; Now, if we are in active mode, then we have to send a SYN to the specified remote port
390
	mov	eax, EMPTY_QUEUE
391
	call	dequeue
392
	cmp	ax, NO_BUFFER
393
	je	.exit
261 hidnplayr 394
 
907 mikedld 395
	push	eax
261 hidnplayr 396
 
907 mikedld 397
	mov	bl, TH_SYN
398
	xor	ecx, ecx
399
	stdcall build_tcp_packet, [sockAddr]
261 hidnplayr 400
 
907 mikedld 401
	mov	eax, NET1OUT_QUEUE
402
	mov	edx, [stack_ip]
403
	mov	ecx, [sockAddr]
404
	cmp	edx, [ecx + SOCKET.RemoteIP]
405
	jne	.not_local
406
	mov	eax, IPIN_QUEUE
261 hidnplayr 407
 
907 mikedld 408
  .not_local:
409
	; Send it.
410
	pop	ebx
411
	call	queue
261 hidnplayr 412
 
907 mikedld 413
	mov	esi, [sockAddr]
261 hidnplayr 414
 
907 mikedld 415
	; increment SND.NXT in socket
416
	add	esi, SOCKET.SND_NXT
417
	call	inc_inet_esi
261 hidnplayr 418
 
907 mikedld 419
  .exit:
420
	mov	ebx, [sockAddr]
421
	mov	[ebx + SOCKET.Status], SOCK_OPEN
422
	;pop     eax      ; Get the socket number back, so we can return it
423
	stdcall net_socket_addr_to_num, ebx
424
	ret
261 hidnplayr 425
 
907 mikedld 426
  .error:
427
	DEBUGF	1, "K : socket_open_tcp (fail)\n"
428
	or	eax, -1
429
	ret
430
endp
261 hidnplayr 431
 
432
 
433
;***************************************************************************
434
;   Function
435
;      socket_close
436
;
437
;   Description
438
;       socket # in ebx
439
;       returns 0 for ok, -1 for socket not open (fail)
440
;
441
;***************************************************************************
907 mikedld 442
proc socket_close stdcall
443
	DEBUGF	1, "K : socket_close (0x%x)\n", ebx
444
	stdcall net_socket_num_to_addr, ebx
445
	or	eax, eax
446
	jz	.error
261 hidnplayr 447
 
907 mikedld 448
	cmp	[eax + SOCKET.Status], dword SOCK_EMPTY
449
	jz	.error
261 hidnplayr 450
 
907 mikedld 451
	; Clear the socket varaibles
452
	stdcall net_socket_free, eax
453
;        mov     edi, eax
454
;        xor     eax, eax
455
;        mov     ecx, SOCKETHEADERSIZE
456
;        cld
457
;        rep     stosb
261 hidnplayr 458
 
907 mikedld 459
	xor	eax, eax
460
	ret
261 hidnplayr 461
 
907 mikedld 462
  .error:
463
	DEBUGF	1, "K : socket_close (fail)\n"
464
	or	eax, -1
465
	ret
466
endp
261 hidnplayr 467
 
907 mikedld 468
 
261 hidnplayr 469
;***************************************************************************
470
;   Function
471
;      socket_close_tcp
472
;
473
;   Description
474
;       socket # in ebx
475
;       returns 0 for ok, -1 for socket not open (fail)
476
;
477
;***************************************************************************
907 mikedld 478
proc socket_close_tcp stdcall
479
local sockAddr dd ?
480
	DEBUGF	1, "K : socket_close_tcp (0x%x)\n", ebx
481
	; first, remove any resend entries
482
	pusha
261 hidnplayr 483
 
907 mikedld 484
	mov	esi, resendQ
485
	mov	ecx, 0
261 hidnplayr 486
 
907 mikedld 487
  .next_resendq:
488
	cmp	ecx, NUMRESENDENTRIES
489
	je	.last_resendq	    ; None left
490
	;cmp     [esi], bl                               ; XTODO: bl -> ebx
491
	cmp	[esi + 4], ebx
492
	je	@f		    ; found one
493
	inc	ecx
494
	add	esi, 8
495
	jmp	.next_resendq
261 hidnplayr 496
 
907 mikedld 497
    ;@@: mov     byte[esi], 0xff                         ; XTODO: 0xff -> 0
498
    @@: mov	dword[esi + 4], 0
499
	inc	ecx
500
	add	esi, 8
501
	jmp	.next_resendq
261 hidnplayr 502
 
907 mikedld 503
  .last_resendq:
504
	popa
261 hidnplayr 505
 
907 mikedld 506
	stdcall net_socket_num_to_addr, ebx
507
	or	eax, eax
508
	jz	.error
261 hidnplayr 509
 
907 mikedld 510
	mov	ebx, eax
511
	mov	[sockAddr], eax
512
	cmp	[ebx + SOCKET.Status], SOCK_EMPTY
513
	je	.error
261 hidnplayr 514
 
907 mikedld 515
	cmp	[ebx + SOCKET.TCBState], TCB_LISTEN		;xxx
516
	je	.destroy_tcb					;xxx
517
	cmp	[ebx + SOCKET.TCBState], TCB_SYN_SENT		;xxx
518
	je	.destroy_tcb					;xxx
261 hidnplayr 519
 
907 mikedld 520
	; Now construct the response, and queue for sending by IP
521
	mov	eax, EMPTY_QUEUE
522
	call	dequeue
523
	cmp	ax, NO_BUFFER
524
	je	.error
261 hidnplayr 525
 
907 mikedld 526
	push	eax
261 hidnplayr 527
 
907 mikedld 528
;xxx    mov     bl, TH_FIN + TH_ACK
529
	mov	bl, TH_FIN					;xxx
530
	xor	ecx, ecx
531
	xor	esi, esi
532
	stdcall build_tcp_packet, [sockAddr]
261 hidnplayr 533
 
907 mikedld 534
	mov	 ebx, [sockAddr]
535
	; increament SND.NXT in socket
536
	lea	esi, [ebx + SOCKET.SND_NXT]
537
	call	inc_inet_esi
261 hidnplayr 538
 
907 mikedld 539
	; Get the socket state
540
	mov	eax, [ebx + SOCKET.TCBState]
541
;xxx    cmp     eax, TCB_LISTEN
542
;xxx    je      .destroy_tcb
543
;xxx    cmp     eax, TCB_SYN_SENT
544
;xxx    je      .destroy_tcb
545
	cmp	eax, TCB_SYN_RECEIVED
546
	je	.fin_wait_1
547
	cmp	eax, TCB_ESTABLISHED
548
	je	.fin_wait_1
261 hidnplayr 549
 
907 mikedld 550
	; assume CLOSE WAIT
551
	; Send a fin, then enter last-ack state
552
	; TODO: check if it's really a TCB_CLOSE_WAIT
553
	mov	[ebx + SOCKET.TCBState], TCB_LAST_ACK
554
	jmp	.send
261 hidnplayr 555
 
907 mikedld 556
  .fin_wait_1:
557
	; Send a fin, then enter finwait2 state
558
	mov	[ebx + SOCKET.TCBState], TCB_FIN_WAIT_1
261 hidnplayr 559
 
907 mikedld 560
  .send:
561
	mov	eax, NET1OUT_QUEUE
562
	mov	edx, [stack_ip]
563
	mov	ecx, [sockAddr]
564
	cmp	edx, [ecx + SOCKET.RemoteIP]
565
	jne	.not_local
566
	mov	eax, IPIN_QUEUE
261 hidnplayr 567
 
907 mikedld 568
  .not_local:
569
	; Send it.
570
	pop	ebx
571
	call	queue
572
	jmp	.exit
261 hidnplayr 573
 
907 mikedld 574
  .destroy_tcb:
575
;xxx    pop     eax
261 hidnplayr 576
 
907 mikedld 577
	; Clear the socket variables
578
;xxx    stdcall net_socket_free, [sockAddr]
579
	stdcall net_socket_free, ebx
261 hidnplayr 580
 
907 mikedld 581
  .exit:
582
	xor	eax, eax
583
	ret
261 hidnplayr 584
 
907 mikedld 585
  .error:
586
	DEBUGF	1, "K : socket_close_tcp (fail)\n"
587
	or	eax, -1
588
	ret
589
endp
261 hidnplayr 590
 
591
 
592
;***************************************************************************
593
;   Function
594
;      socket_poll
595
;
596
;   Description
597
;       socket # in ebx
598
;       returns count in eax.
599
;
600
;***************************************************************************
907 mikedld 601
proc socket_poll stdcall
602
;        DEBUGF  1, "socket_poll(0x%x)\n", ebx
603
	stdcall net_socket_num_to_addr, ebx
604
	or	eax, eax
605
	jz	.error
261 hidnplayr 606
 
907 mikedld 607
	mov	eax, [eax + SOCKET.rxDataCount]
608
	ret
261 hidnplayr 609
 
907 mikedld 610
  .error:
611
	xor	eax, eax
612
	ret
613
endp
261 hidnplayr 614
 
615
 
616
;***************************************************************************
617
;   Function
618
;      socket_status
619
;
620
;   Description
621
;       socket # in ebx
622
;       returns TCB state in eax.
623
;
624
;***************************************************************************
907 mikedld 625
proc socket_status stdcall
626
;;       DEBUGF  1, "socket_status(0x%x)\n", ebx
627
	stdcall net_socket_num_to_addr, ebx
628
	or	eax, eax
629
	jz	.error
261 hidnplayr 630
 
907 mikedld 631
	mov	eax, [eax + SOCKET.TCBState]
632
	ret
261 hidnplayr 633
 
907 mikedld 634
  .error:
635
	xor	eax, eax
636
	ret
637
endp
261 hidnplayr 638
 
907 mikedld 639
;    Index2RealAddr ebx
640
;    mov     eax, [ebx + SOCKET.TCBState]
641
;
642
;    ret
261 hidnplayr 643
 
907 mikedld 644
 
261 hidnplayr 645
;***************************************************************************
646
;   Function
647
;      socket_read
648
;
649
;   Description
650
;       socket # in ebx
651
;       returns # of bytes remaining in eax, data in bl
652
;
653
;***************************************************************************
907 mikedld 654
proc socket_read stdcall
655
;        DEBUGF  1, "socket_read(0x%x)\n", ebx
656
	stdcall net_socket_num_to_addr, ebx
657
	or	eax, eax
658
	jz	.error
261 hidnplayr 659
 
907 mikedld 660
	mov	ebx, eax
661
	mov	eax, [ebx + SOCKET.rxDataCount] 	; get count of bytes
662
	test	eax, eax
663
	jz	.error
261 hidnplayr 664
 
907 mikedld 665
	dec	eax
915 mikedld 666
	mov	esi, ebx				; esi is address of socket
907 mikedld 667
	mov	[ebx + SOCKET.rxDataCount], eax 	; store new count
915 mikedld 668
	movzx	ebx, byte[ebx + SOCKET.rxData]		; get the byte
261 hidnplayr 669
 
915 mikedld 670
	mov	ecx, SOCKETBUFFSIZE - SOCKET.rxData - 1
671
	lea	edi, [esi + SOCKET.rxData]
907 mikedld 672
	lea	esi, [edi + 1]
673
	cld
915 mikedld 674
	push	ecx
675
	shr	ecx, 2
907 mikedld 676
	rep	movsd
915 mikedld 677
	pop	ecx
678
	and	ecx, 3
679
	rep	movsb
261 hidnplayr 680
 
907 mikedld 681
	ret
261 hidnplayr 682
 
907 mikedld 683
  .error:
684
	xor	eax, eax
685
	xor	ebx, ebx
686
	ret
687
endp
261 hidnplayr 688
 
689
 
323 hidnplayr 690
;***************************************************************************
691
;   Function
692
;      socket_read_packet
693
;
694
;   Description
695
;       socket # in ebx
696
;       datapointer # in ecx
697
;       buffer size in edx
698
;       returns # of bytes copied in eax
699
;
700
;***************************************************************************
907 mikedld 701
proc socket_read_packet stdcall
702
;        DEBUGF  1, "socket_read_packet(0x%x)\n", ebx
703
	stdcall net_socket_num_to_addr, ebx		   ; get real socket address
704
	or	eax, eax
705
	jz	.error
261 hidnplayr 706
 
907 mikedld 707
	mov	ebx, eax
708
	mov	eax, [ebx + SOCKET.rxDataCount] 	   ; get count of bytes
709
	test	eax, eax				   ; if count of bytes is zero..
710
	jz	.exit					   ; exit function (eax will be zero)
323 hidnplayr 711
 
907 mikedld 712
	test	edx, edx				   ; if buffer size is zero, copy all data
713
	jz	.copy_all_bytes
714
	cmp	edx, eax				   ; if buffer size is larger then the bytes of data, copy all data
715
	jge	.copy_all_bytes
323 hidnplayr 716
 
907 mikedld 717
	sub	eax, edx				   ; store new count (data bytes in buffer - bytes we're about to copy)
718
	mov	[ebx + SOCKET.rxDataCount], eax 	   ;
719
	push	eax
720
	mov	eax, edx				   ; number of bytes we want to copy must be in eax
721
	call	.start_copy				   ; copy to the application
323 hidnplayr 722
 
907 mikedld 723
	mov	esi, ebx				   ; now we're going to copy the remaining bytes to the beginning
915 mikedld 724
	add	esi, SOCKET.rxData			   ; we dont need to copy the header
907 mikedld 725
	mov	edi, esi				   ; edi is where we're going to copy to
726
	add	esi, edx				   ; esi is from where we copy
727
	pop	ecx					   ; count of bytes we have left
728
	push	ecx					   ; push it again so we can re-use it later
729
	shr	ecx, 2					   ; divide eax by 4
730
	cld
731
	rep	movsd					   ; copy all full dwords
732
	pop	ecx
733
	and	ecx, 3
734
	rep	movsb					   ; copy remaining bytes
323 hidnplayr 735
 
907 mikedld 736
  .exit:
737
	ret						   ; at last, exit
323 hidnplayr 738
 
907 mikedld 739
  .error:
740
	xor	eax, eax
741
	ret
323 hidnplayr 742
 
907 mikedld 743
  .copy_all_bytes:
744
	xor	esi, esi
745
	mov	[ebx + SOCKET.rxDataCount], esi 	   ; store new count (zero)
746
	call	.start_copy
747
	ret
323 hidnplayr 748
 
907 mikedld 749
  .start_copy:
750
	mov	edi, ecx
751
	mov	esi, ebx
915 mikedld 752
	add	esi, SOCKET.rxData			   ; we dont need to copy the header
907 mikedld 753
	mov	ecx, eax				   ; eax is count of bytes
754
	push	ecx
755
	shr	ecx, 2					   ; divide eax by 4
756
	cld						   ; copy all full dwords
757
	rep	movsd
758
	pop	ecx
759
	and	ecx, 3
760
	rep	movsb					   ; copy the rest bytes
761
	retn						   ; exit, or go back to shift remaining bytes if any
762
endp
323 hidnplayr 763
 
764
 
261 hidnplayr 765
;***************************************************************************
766
;   Function
767
;      socket_write
768
;
769
;   Description
770
;       socket in ebx
771
;       # of bytes to write in ecx
772
;       pointer to data in edx
773
;       returns 0 in eax ok, -1 == failed ( invalid socket, or
774
;       could not queue IP packet )
775
;
776
;***************************************************************************
907 mikedld 777
proc socket_write stdcall
778
;        DEBUGF  1, "socket_write(0x%x)\n", ebx
779
	stdcall net_socket_num_to_addr, ebx		   ; get real socket address
780
	or	eax, eax
781
	jz	.error
261 hidnplayr 782
 
907 mikedld 783
	mov	ebx, eax
261 hidnplayr 784
 
907 mikedld 785
	; If the socket is invalid, return with an error code
786
	cmp	[ebx + SOCKET.Status], SOCK_EMPTY
787
	je	.error
261 hidnplayr 788
 
907 mikedld 789
	mov	eax, EMPTY_QUEUE
790
	call	dequeue
791
	cmp	ax, NO_BUFFER
792
	je	.error
261 hidnplayr 793
 
907 mikedld 794
	; Save the queue entry number
795
	push	eax
261 hidnplayr 796
 
907 mikedld 797
	; save the pointers to the data buffer & size
798
	push	edx
799
	push	ecx
261 hidnplayr 800
 
907 mikedld 801
	; convert buffer pointer eax to the absolute address
802
	mov	ecx, IPBUFFSIZE
803
	mul	ecx
804
	add	eax, IPbuffs
261 hidnplayr 805
 
907 mikedld 806
	mov	edx, eax
261 hidnplayr 807
 
907 mikedld 808
	; So, ebx holds the socket ptr, edx holds the IPbuffer ptr
261 hidnplayr 809
 
907 mikedld 810
	; Fill in the IP header (some data is in the socket descriptor)
811
	mov	eax, [ebx + SOCKET.LocalIP]
812
	mov	[edx + IP_PACKET.SourceAddress], eax
813
	mov	eax, [ebx + SOCKET.RemoteIP]
814
	mov	[edx + IP_PACKET.DestinationAddress], eax
261 hidnplayr 815
 
907 mikedld 816
	mov	[edx + IP_PACKET.VersionAndIHL], 0x45
817
	mov	[edx + IP_PACKET.TypeOfService], 0
261 hidnplayr 818
 
907 mikedld 819
	pop	eax		      ; Get the UDP data length
820
	push	eax
261 hidnplayr 821
 
907 mikedld 822
	add	eax, 20 + 8	      ; add IP header and UDP header lengths
823
	xchg	al, ah
824
	mov	[edx + IP_PACKET.TotalLength], ax
825
	xor	eax, eax
826
	mov	[edx + IP_PACKET.Identification], ax
827
	mov	[edx + IP_PACKET.FlagsAndFragmentOffset], 0x0040
828
	mov	[edx + IP_PACKET.TimeToLive], 0x20
829
	mov	[edx + IP_PACKET.Protocol], PROTOCOL_UDP
261 hidnplayr 830
 
907 mikedld 831
	; Checksum left unfilled
832
	mov	[edx + IP_PACKET.HeaderChecksum], ax
261 hidnplayr 833
 
907 mikedld 834
	; Fill in the UDP header (some data is in the socket descriptor)
835
	mov	ax, [ebx + SOCKET.LocalPort]
836
	mov	[edx + 20 + UDP_PACKET.SourcePort], ax
261 hidnplayr 837
 
907 mikedld 838
	mov	ax, [ebx + SOCKET.RemotePort]
839
	mov	[edx + 20 + UDP_PACKET.DestinationPort], ax
261 hidnplayr 840
 
907 mikedld 841
	pop	eax
842
	push	eax
261 hidnplayr 843
 
907 mikedld 844
	add	eax, 8
845
	xchg	al, ah
846
	mov	[edx + 20 + UDP_PACKET.Length], ax
261 hidnplayr 847
 
907 mikedld 848
	; Checksum left unfilled
849
	xor	eax, eax
850
	mov	[edx + 20 + UDP_PACKET.Checksum], ax
261 hidnplayr 851
 
907 mikedld 852
	pop	ecx		     ; count of bytes to send
853
	mov	ebx, ecx	     ; need the length later
854
	pop	eax		     ; get callers ptr to data to send
261 hidnplayr 855
 
907 mikedld 856
	; Get the address of the callers data
857
	mov	edi, [TASK_BASE]
858
	add	edi, TASKDATA.mem_start
859
	add	eax, [edi]
860
	mov	esi, eax
261 hidnplayr 861
 
907 mikedld 862
	mov	edi, edx
863
	add	edi, 28
864
	cld
865
	rep	movsb		    ; copy the data across
261 hidnplayr 866
 
907 mikedld 867
	; we have edx as IPbuffer ptr.
868
	; Fill in the UDP checksum
869
	; First, fill in pseudoheader
870
	mov	eax, [edx + IP_PACKET.SourceAddress]
871
	mov	[pseudoHeader], eax
872
	mov	eax, [edx + IP_PACKET.DestinationAddress]
873
	mov	[pseudoHeader + 4], eax
874
	mov	word[pseudoHeader + 8], PROTOCOL_UDP shl 8 + 0	    ; 0 + protocol
875
	add	ebx, 8
876
	mov	eax, ebx
877
	xchg	al, ah
878
	mov	[pseudoHeader + 10], ax
261 hidnplayr 879
 
907 mikedld 880
	mov	eax, pseudoHeader
881
	mov	[checkAdd1], eax
882
	mov	[checkSize1], word 12
883
	mov	eax, edx
884
	add	eax, 20
885
	mov	[checkAdd2], eax
886
	mov	eax, ebx
887
	mov	[checkSize2], ax      ; was eax!! mjh 8/7/02
261 hidnplayr 888
 
907 mikedld 889
	call	checksum
261 hidnplayr 890
 
907 mikedld 891
	; store it in the UDP checksum ( in the correct order! )
892
	mov	ax, [checkResult]
261 hidnplayr 893
 
907 mikedld 894
	; If the UDP checksum computes to 0, we must make it 0xffff
895
	; (0 is reserved for 'not used')
896
	test	ax, ax
897
	jnz	@f
898
	mov	ax, 0xffff
261 hidnplayr 899
 
907 mikedld 900
    @@: xchg	al, ah
901
	mov	[edx + 20 + UDP_PACKET.Checksum], ax
261 hidnplayr 902
 
907 mikedld 903
	; Fill in the IP header checksum
904
	GET_IHL ecx,edx 	     ; get IP-Header length
905
	stdcall checksum_jb,edx,ecx  ; buf_ptr, buf_size
906
	xchg	al, ah
907
	mov	[edx + IP_PACKET.HeaderChecksum], ax
261 hidnplayr 908
 
907 mikedld 909
	; Check destination IP address.
910
	; If it is the local host IP, route it back to IP_RX
261 hidnplayr 911
 
907 mikedld 912
	pop	ebx
261 hidnplayr 913
 
907 mikedld 914
	mov	eax, NET1OUT_QUEUE
915
	mov	ecx, [edx + SOCKET.RemoteIP]
916
	mov	edx, [stack_ip]
917
	cmp	edx, ecx
918
	jne	.not_local
919
	mov	eax, IPIN_QUEUE
261 hidnplayr 920
 
907 mikedld 921
  .not_local:
922
	; Send it.
923
	call	queue
261 hidnplayr 924
 
907 mikedld 925
	xor	eax, eax
926
	ret
261 hidnplayr 927
 
907 mikedld 928
  .error:
929
	or	eax, -1
930
	ret
931
endp
261 hidnplayr 932
 
933
 
934
;***************************************************************************
935
;   Function
936
;      socket_write_tcp
937
;
938
;   Description
939
;       socket in ebx
940
;       # of bytes to write in ecx
941
;       pointer to data in edx
942
;       returns 0 in eax ok, -1 == failed ( invalid socket, or
943
;       could not queue IP packet )
944
;
945
;***************************************************************************
907 mikedld 946
proc socket_write_tcp stdcall
947
local sockAddr dd ?
261 hidnplayr 948
 
907 mikedld 949
;        DEBUGF  1, "socket_write_tcp(0x%x)\n", ebx
950
	stdcall net_socket_num_to_addr, ebx
951
	or	eax, eax
952
	jz	.error
261 hidnplayr 953
 
907 mikedld 954
	mov	ebx, eax
955
	mov	[sockAddr], ebx
261 hidnplayr 956
 
907 mikedld 957
	; If the socket is invalid, return with an error code
958
	cmp	[ebx + SOCKET.Status], SOCK_EMPTY
959
	je	.error
261 hidnplayr 960
 
907 mikedld 961
	; If the sockets window timer is nonzero, do not queue packet
962
	; TODO - done
963
	cmp	[ebx + SOCKET.wndsizeTimer], 0
964
	jne	.error
261 hidnplayr 965
 
907 mikedld 966
	mov	eax, EMPTY_QUEUE
967
	call	dequeue
968
	cmp	ax, NO_BUFFER
969
	je	.error
261 hidnplayr 970
 
907 mikedld 971
	push	eax
261 hidnplayr 972
 
907 mikedld 973
	; Get the address of the callers data
974
	mov	edi, [TASK_BASE]
975
	add	edi, TASKDATA.mem_start
976
	add	edx, [edi]
977
	mov	esi, edx
261 hidnplayr 978
 
907 mikedld 979
	pop	eax
980
	push	eax
261 hidnplayr 981
 
907 mikedld 982
	push	ecx
983
	mov	bl, TH_ACK
984
	stdcall build_tcp_packet, [sockAddr]
985
	pop	ecx
261 hidnplayr 986
 
907 mikedld 987
	; Check destination IP address.
988
	; If it is the local host IP, route it back to IP_RX
261 hidnplayr 989
 
907 mikedld 990
	pop	ebx
991
	push	ecx
261 hidnplayr 992
 
907 mikedld 993
	mov	eax, NET1OUT_QUEUE
994
	mov	edx, [stack_ip]
995
	mov	ecx, [sockAddr]
996
	cmp	edx, [ecx + SOCKET.RemoteIP]
997
	jne	.not_local
998
	mov	eax, IPIN_QUEUE
261 hidnplayr 999
 
907 mikedld 1000
  .not_local:
1001
	pop	ecx
1002
	push	ebx		    ; save ipbuffer number
261 hidnplayr 1003
 
907 mikedld 1004
	call	queue
261 hidnplayr 1005
 
907 mikedld 1006
	mov	esi, [sockAddr]
261 hidnplayr 1007
 
907 mikedld 1008
	; increament SND.NXT in socket
1009
	; Amount to increment by is in ecx
1010
	add	esi, SOCKET.SND_NXT
1011
	call	add_inet_esi
261 hidnplayr 1012
 
907 mikedld 1013
	pop	ebx
261 hidnplayr 1014
 
907 mikedld 1015
	; Copy the IP buffer to a resend queue
1016
	; If there isn't one, dont worry about it for now
1017
	mov	esi, resendQ
1018
	mov	ecx, 0
261 hidnplayr 1019
 
907 mikedld 1020
  .next_resendq:
1021
	cmp	ecx, NUMRESENDENTRIES
1022
	je	.exit		   ; None found
1023
	;cmp     byte[esi], 0xff                                 ; XTODO: 0xff -> 0
1024
	cmp	dword[esi + 4], 0
1025
	je	@f		   ; found one
1026
	inc	ecx
1027
	add	esi, 8
1028
	jmp	.next_resendq
261 hidnplayr 1029
 
907 mikedld 1030
    @@: push	ebx
261 hidnplayr 1031
 
907 mikedld 1032
	; OK, we have a buffer descriptor ptr in esi.
1033
	; resend entry # in ecx
1034
	;  Populate it
1035
	;  socket #
1036
	;  retries count
1037
	;  retry time
1038
	;  fill IP buffer associated with this descriptor
261 hidnplayr 1039
 
907 mikedld 1040
	stdcall net_socket_addr_to_num, [sockAddr]
1041
	;mov     [esi], al                               ; XTODO: al -> eax
1042
	mov	[esi + 4], eax
1043
	mov	byte[esi + 1], TCP_RETRIES
1044
	mov	word[esi + 2], TCP_TIMEOUT
261 hidnplayr 1045
 
907 mikedld 1046
	inc	ecx
1047
	; Now get buffer location, and copy buffer across. argh! more copying,,
1048
	mov	edi, resendBuffer - IPBUFFSIZE
261 hidnplayr 1049
 
907 mikedld 1050
    @@: add	edi, IPBUFFSIZE
1051
	loop	@b
261 hidnplayr 1052
 
907 mikedld 1053
	; we have dest buffer location in edi
1054
	pop	eax
1055
	; convert source buffer pointer eax to the absolute address
1056
	mov	ecx, IPBUFFSIZE
1057
	mul	ecx
1058
	add	eax, IPbuffs
1059
	mov	esi, eax
261 hidnplayr 1060
 
907 mikedld 1061
	; do copy
1062
	mov	ecx, IPBUFFSIZE
1063
	cld
1064
	rep	movsb
261 hidnplayr 1065
 
907 mikedld 1066
  .exit:
1067
	xor	eax, eax
1068
	ret
261 hidnplayr 1069
 
907 mikedld 1070
  .error:
1071
	or	eax, -1
1072
	ret
1073
endp