Subversion Repositories Kolibri OS

Rev

Rev 738 | 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: 907 $
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
{
87
   .Status		    dd	 ?  ;+00 - Status ( of this buffer )
379 serge 88
   .PID 		    dd	 ?  ;+04 - Application Process ID
907 mikedld 89
   .LocalIP		    dd	 ?  ;+08 - Local IP Address
323 hidnplayr 90
   .LocalPort		    dw	 ?  ;+12 - Local Port
91
   .RemoteIP		    dd	 ?  ;+16 - Remote IP Address
92
   .RemotePort		    dw	 ?  ;+20 - Remote Port
907 mikedld 93
   .OrigRemoteIP	    dd	 ?
94
   .OrigRemotePort	    dw	 ?
323 hidnplayr 95
   .rxDataCount 	    dd	 ?  ;+24 - Rx Data Count
96
   .TCBState		    dd	 ?  ;+28 - TCB STATE
379 serge 97
   .TCBTimer		    dd	 ?  ;+32 - TCB Timer (seconds)
323 hidnplayr 98
   .ISS 		    dd	 ?  ;+36 - Initial Send Sequence
99
   .IRS 		    dd	 ?  ;+40 - Initial Receive Sequence
100
   .SND_UNA		    dd	 ?  ;+44 - Sequence number of unack'ed sent packets
379 serge 101
   .SND_NXT		    dd	 ?  ;+48 - Next send sequence number to use
323 hidnplayr 102
   .SND_WND		    dd	 ?  ;+52 - Send window
103
   .RCV_NXT		    dd	 ?  ;+56 - Next receive sequence number to use
104
   .RCV_WND		    dd	 ?  ;+60 - Receive window
105
   .SEG_LEN		    dd	 ?  ;+64 - Segment length
106
   .SEG_WND		    dd	 ?  ;+68 - Segment window
379 serge 107
   .wndsizeTimer	    dd	 ?  ;+72 - Retransmit queue # NOW WINDOW SIZE TIMER
907 mikedld 108
   .PrevPtr		    dd	 ?
109
   .NextPtr		    dd	 ?
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
	;or      eax, -1
612
	xor	eax, eax
613
	ret
614
endp
261 hidnplayr 615
 
616
 
617
;***************************************************************************
618
;   Function
619
;      socket_status
620
;
621
;   Description
622
;       socket # in ebx
623
;       returns TCB state in eax.
624
;
625
;***************************************************************************
907 mikedld 626
proc socket_status stdcall
627
;;       DEBUGF  1, "socket_status(0x%x)\n", ebx
628
	stdcall net_socket_num_to_addr, ebx
629
	or	eax, eax
630
	jz	.error
261 hidnplayr 631
 
907 mikedld 632
	mov	eax, [eax + SOCKET.TCBState]
633
	ret
261 hidnplayr 634
 
907 mikedld 635
  .error:
636
	;or      eax, -1
637
	xor	eax, eax
638
	ret
639
endp
261 hidnplayr 640
 
907 mikedld 641
;    Index2RealAddr ebx
642
;    mov     eax, [ebx + SOCKET.TCBState]
643
;
644
;    ret
261 hidnplayr 645
 
907 mikedld 646
 
261 hidnplayr 647
;***************************************************************************
648
;   Function
649
;      socket_read
650
;
651
;   Description
652
;       socket # in ebx
653
;       returns # of bytes remaining in eax, data in bl
654
;
655
;***************************************************************************
907 mikedld 656
proc socket_read stdcall
657
;        DEBUGF  1, "socket_read(0x%x)\n", ebx
658
	stdcall net_socket_num_to_addr, ebx
659
	or	eax, eax
660
	jz	.error
261 hidnplayr 661
 
907 mikedld 662
	mov	ebx, eax
663
	mov	eax, [ebx + SOCKET.rxDataCount] 	; get count of bytes
664
	test	eax, eax
665
	jz	.error
261 hidnplayr 666
 
907 mikedld 667
	dec	eax
668
	mov	esi, ebx	    ; esi is address of socket
669
	mov	[ebx + SOCKET.rxDataCount], eax 	; store new count
670
	;movzx   ebx, byte[ebx + SOCKET.rxData]  ; get the byte
671
	movzx	ebx, byte[ebx + SOCKETHEADERSIZE]  ; get the byte
672
	add	esi, SOCKETHEADERSIZE
673
	mov	edi, esi
674
	inc	esi
261 hidnplayr 675
 
907 mikedld 676
	mov	ecx, (SOCKETBUFFSIZE - SOCKETHEADERSIZE) / 4
677
	lea	edi, [ebx + SOCKETHEADERSIZE]
678
	lea	esi, [edi + 1]
679
	cld
680
	rep	movsd
261 hidnplayr 681
 
907 mikedld 682
	ret
261 hidnplayr 683
 
907 mikedld 684
  .error:
685
	;or      eax, -1
686
	xor	eax, eax
687
	xor	ebx, ebx
688
	ret
689
endp
261 hidnplayr 690
 
691
 
323 hidnplayr 692
;***************************************************************************
693
;   Function
694
;      socket_read_packet
695
;
696
;   Description
697
;       socket # in ebx
698
;       datapointer # in ecx
699
;       buffer size in edx
700
;       returns # of bytes copied in eax
701
;
702
;***************************************************************************
907 mikedld 703
proc socket_read_packet stdcall
704
;        DEBUGF  1, "socket_read_packet(0x%x)\n", ebx
705
	stdcall net_socket_num_to_addr, ebx		   ; get real socket address
706
	or	eax, eax
707
	jz	.error
261 hidnplayr 708
 
907 mikedld 709
	mov	ebx, eax
710
	mov	eax, [ebx + SOCKET.rxDataCount] 	   ; get count of bytes
711
	test	eax, eax				   ; if count of bytes is zero..
712
	jz	.exit					   ; exit function (eax will be zero)
323 hidnplayr 713
 
907 mikedld 714
	test	edx, edx				   ; if buffer size is zero, copy all data
715
	jz	.copy_all_bytes
716
	cmp	edx, eax				   ; if buffer size is larger then the bytes of data, copy all data
717
	jge	.copy_all_bytes
323 hidnplayr 718
 
907 mikedld 719
	sub	eax, edx				   ; store new count (data bytes in buffer - bytes we're about to copy)
720
	mov	[ebx + SOCKET.rxDataCount], eax 	   ;
721
	push	eax
722
	mov	eax, edx				   ; number of bytes we want to copy must be in eax
723
	call	.start_copy				   ; copy to the application
323 hidnplayr 724
 
907 mikedld 725
	mov	esi, ebx				   ; now we're going to copy the remaining bytes to the beginning
726
	add	esi, SOCKETHEADERSIZE			   ; we dont need to copy the header
727
	mov	edi, esi				   ; edi is where we're going to copy to
728
	add	esi, edx				   ; esi is from where we copy
729
	pop	ecx					   ; count of bytes we have left
730
	push	ecx					   ; push it again so we can re-use it later
731
	shr	ecx, 2					   ; divide eax by 4
732
	cld
733
	rep	movsd					   ; copy all full dwords
734
	pop	ecx
735
	and	ecx, 3
736
	rep	movsb					   ; copy remaining bytes
323 hidnplayr 737
 
907 mikedld 738
  .exit:
739
	ret						   ; at last, exit
323 hidnplayr 740
 
907 mikedld 741
  .error:
742
	;or      eax, -1
743
	xor	eax, eax
744
	ret
323 hidnplayr 745
 
907 mikedld 746
  .copy_all_bytes:
747
	xor	esi, esi
748
	mov	[ebx + SOCKET.rxDataCount], esi 	   ; store new count (zero)
749
	call	.start_copy
750
	ret
323 hidnplayr 751
 
907 mikedld 752
  .start_copy:
753
	mov	edi, ecx
754
	mov	esi, ebx
755
	add	esi, SOCKETHEADERSIZE			   ; we dont need to copy the header
756
	mov	ecx, eax				   ; eax is count of bytes
757
	push	ecx
758
	shr	ecx, 2					   ; divide eax by 4
759
	cld						   ; copy all full dwords
760
	rep	movsd
761
	pop	ecx
762
	and	ecx, 3
763
	rep	movsb					   ; copy the rest bytes
764
	retn						   ; exit, or go back to shift remaining bytes if any
765
endp
323 hidnplayr 766
 
767
 
261 hidnplayr 768
;***************************************************************************
769
;   Function
770
;      socket_write
771
;
772
;   Description
773
;       socket in ebx
774
;       # of bytes to write in ecx
775
;       pointer to data in edx
776
;       returns 0 in eax ok, -1 == failed ( invalid socket, or
777
;       could not queue IP packet )
778
;
779
;***************************************************************************
907 mikedld 780
proc socket_write stdcall
781
;        DEBUGF  1, "socket_write(0x%x)\n", ebx
782
	stdcall net_socket_num_to_addr, ebx		   ; get real socket address
783
	or	eax, eax
784
	jz	.error
261 hidnplayr 785
 
907 mikedld 786
	mov	ebx, eax
261 hidnplayr 787
 
907 mikedld 788
	; If the socket is invalid, return with an error code
789
	cmp	[ebx + SOCKET.Status], SOCK_EMPTY
790
	je	.error
261 hidnplayr 791
 
907 mikedld 792
	mov	eax, EMPTY_QUEUE
793
	call	dequeue
794
	cmp	ax, NO_BUFFER
795
	je	.error
261 hidnplayr 796
 
907 mikedld 797
	; Save the queue entry number
798
	push	eax
261 hidnplayr 799
 
907 mikedld 800
	; save the pointers to the data buffer & size
801
	push	edx
802
	push	ecx
261 hidnplayr 803
 
907 mikedld 804
	; convert buffer pointer eax to the absolute address
805
	mov	ecx, IPBUFFSIZE
806
	mul	ecx
807
	add	eax, IPbuffs
261 hidnplayr 808
 
907 mikedld 809
	mov	edx, eax
261 hidnplayr 810
 
907 mikedld 811
	; So, ebx holds the socket ptr, edx holds the IPbuffer ptr
261 hidnplayr 812
 
907 mikedld 813
	; Fill in the IP header (some data is in the socket descriptor)
814
	mov	eax, [ebx + SOCKET.LocalIP]
815
	mov	[edx + IP_PACKET.SourceAddress], eax
816
	mov	eax, [ebx + SOCKET.RemoteIP]
817
	mov	[edx + IP_PACKET.DestinationAddress], eax
261 hidnplayr 818
 
907 mikedld 819
	mov	[edx + IP_PACKET.VersionAndIHL], 0x45
820
	mov	[edx + IP_PACKET.TypeOfService], 0
261 hidnplayr 821
 
907 mikedld 822
	pop	eax		      ; Get the UDP data length
823
	push	eax
261 hidnplayr 824
 
907 mikedld 825
	add	eax, 20 + 8	      ; add IP header and UDP header lengths
826
	xchg	al, ah
827
	mov	[edx + IP_PACKET.TotalLength], ax
828
	xor	eax, eax
829
	mov	[edx + IP_PACKET.Identification], ax
830
	mov	[edx + IP_PACKET.FlagsAndFragmentOffset], 0x0040
831
	mov	[edx + IP_PACKET.TimeToLive], 0x20
832
	mov	[edx + IP_PACKET.Protocol], PROTOCOL_UDP
261 hidnplayr 833
 
907 mikedld 834
	; Checksum left unfilled
835
	mov	[edx + IP_PACKET.HeaderChecksum], ax
261 hidnplayr 836
 
907 mikedld 837
	; Fill in the UDP header (some data is in the socket descriptor)
838
	mov	ax, [ebx + SOCKET.LocalPort]
839
	mov	[edx + 20 + UDP_PACKET.SourcePort], ax
261 hidnplayr 840
 
907 mikedld 841
	mov	ax, [ebx + SOCKET.RemotePort]
842
	mov	[edx + 20 + UDP_PACKET.DestinationPort], ax
261 hidnplayr 843
 
907 mikedld 844
	pop	eax
845
	push	eax
261 hidnplayr 846
 
907 mikedld 847
	add	eax, 8
848
	xchg	al, ah
849
	mov	[edx + 20 + UDP_PACKET.Length], ax
261 hidnplayr 850
 
907 mikedld 851
	; Checksum left unfilled
852
	xor	eax, eax
853
	mov	[edx + 20 + UDP_PACKET.Checksum], ax
261 hidnplayr 854
 
907 mikedld 855
	pop	ecx		     ; count of bytes to send
856
	mov	ebx, ecx	     ; need the length later
857
	pop	eax		     ; get callers ptr to data to send
261 hidnplayr 858
 
907 mikedld 859
	; Get the address of the callers data
860
	mov	edi, [TASK_BASE]
861
	add	edi, TASKDATA.mem_start
862
	add	eax, [edi]
863
	mov	esi, eax
261 hidnplayr 864
 
907 mikedld 865
	mov	edi, edx
866
	add	edi, 28
867
	cld
868
	rep	movsb		    ; copy the data across
261 hidnplayr 869
 
907 mikedld 870
	; we have edx as IPbuffer ptr.
871
	; Fill in the UDP checksum
872
	; First, fill in pseudoheader
873
	mov	eax, [edx + IP_PACKET.SourceAddress]
874
	mov	[pseudoHeader], eax
875
	mov	eax, [edx + IP_PACKET.DestinationAddress]
876
	mov	[pseudoHeader + 4], eax
877
	mov	word[pseudoHeader + 8], PROTOCOL_UDP shl 8 + 0	    ; 0 + protocol
878
	add	ebx, 8
879
	mov	eax, ebx
880
	xchg	al, ah
881
	mov	[pseudoHeader + 10], ax
261 hidnplayr 882
 
907 mikedld 883
	mov	eax, pseudoHeader
884
	mov	[checkAdd1], eax
885
	mov	[checkSize1], word 12
886
	mov	eax, edx
887
	add	eax, 20
888
	mov	[checkAdd2], eax
889
	mov	eax, ebx
890
	mov	[checkSize2], ax      ; was eax!! mjh 8/7/02
261 hidnplayr 891
 
907 mikedld 892
	call	checksum
261 hidnplayr 893
 
907 mikedld 894
	; store it in the UDP checksum ( in the correct order! )
895
	mov	ax, [checkResult]
261 hidnplayr 896
 
907 mikedld 897
	; If the UDP checksum computes to 0, we must make it 0xffff
898
	; (0 is reserved for 'not used')
899
	test	ax, ax
900
	jnz	@f
901
	mov	ax, 0xffff
261 hidnplayr 902
 
907 mikedld 903
    @@: xchg	al, ah
904
	mov	[edx + 20 + UDP_PACKET.Checksum], ax
261 hidnplayr 905
 
907 mikedld 906
	; Fill in the IP header checksum
907
	GET_IHL ecx,edx 	     ; get IP-Header length
908
	stdcall checksum_jb,edx,ecx  ; buf_ptr, buf_size
909
	xchg	al, ah
910
	mov	[edx + IP_PACKET.HeaderChecksum], ax
261 hidnplayr 911
 
907 mikedld 912
	; Check destination IP address.
913
	; If it is the local host IP, route it back to IP_RX
261 hidnplayr 914
 
907 mikedld 915
	pop	ebx
261 hidnplayr 916
 
907 mikedld 917
	mov	eax, NET1OUT_QUEUE
918
	mov	ecx, [edx + SOCKET.RemoteIP]
919
	mov	edx, [stack_ip]
920
	cmp	edx, ecx
921
	jne	.not_local
922
	mov	eax, IPIN_QUEUE
261 hidnplayr 923
 
907 mikedld 924
  .not_local:
925
	; Send it.
926
	call	queue
261 hidnplayr 927
 
907 mikedld 928
	xor	eax, eax
929
	ret
261 hidnplayr 930
 
907 mikedld 931
  .error:
932
	or	eax, -1
933
	ret
934
endp
261 hidnplayr 935
 
936
 
937
;***************************************************************************
938
;   Function
939
;      socket_write_tcp
940
;
941
;   Description
942
;       socket in ebx
943
;       # of bytes to write in ecx
944
;       pointer to data in edx
945
;       returns 0 in eax ok, -1 == failed ( invalid socket, or
946
;       could not queue IP packet )
947
;
948
;***************************************************************************
907 mikedld 949
proc socket_write_tcp stdcall
950
local sockAddr dd ?
261 hidnplayr 951
 
907 mikedld 952
;        DEBUGF  1, "socket_write_tcp(0x%x)\n", ebx
953
	stdcall net_socket_num_to_addr, ebx
954
	or	eax, eax
955
	jz	.error
261 hidnplayr 956
 
907 mikedld 957
	mov	ebx, eax
958
	mov	[sockAddr], ebx
261 hidnplayr 959
 
907 mikedld 960
	; If the socket is invalid, return with an error code
961
	cmp	[ebx + SOCKET.Status], SOCK_EMPTY
962
	je	.error
261 hidnplayr 963
 
907 mikedld 964
	; If the sockets window timer is nonzero, do not queue packet
965
	; TODO - done
966
	cmp	[ebx + SOCKET.wndsizeTimer], 0
967
	jne	.error
261 hidnplayr 968
 
907 mikedld 969
	mov	eax, EMPTY_QUEUE
970
	call	dequeue
971
	cmp	ax, NO_BUFFER
972
	je	.error
261 hidnplayr 973
 
907 mikedld 974
	push	eax
261 hidnplayr 975
 
907 mikedld 976
	; Get the address of the callers data
977
	mov	edi, [TASK_BASE]
978
	add	edi, TASKDATA.mem_start
979
	add	edx, [edi]
980
	mov	esi, edx
261 hidnplayr 981
 
907 mikedld 982
	pop	eax
983
	push	eax
261 hidnplayr 984
 
907 mikedld 985
	push	ecx
986
	mov	bl, TH_ACK
987
	stdcall build_tcp_packet, [sockAddr]
988
	pop	ecx
261 hidnplayr 989
 
907 mikedld 990
	; Check destination IP address.
991
	; If it is the local host IP, route it back to IP_RX
261 hidnplayr 992
 
907 mikedld 993
	pop	ebx
994
	push	ecx
261 hidnplayr 995
 
907 mikedld 996
	mov	eax, NET1OUT_QUEUE
997
	mov	edx, [stack_ip]
998
	mov	ecx, [sockAddr]
999
	cmp	edx, [ecx + SOCKET.RemoteIP]
1000
	jne	.not_local
1001
	mov	eax, IPIN_QUEUE
261 hidnplayr 1002
 
907 mikedld 1003
  .not_local:
1004
	pop	ecx
1005
	push	ebx		    ; save ipbuffer number
261 hidnplayr 1006
 
907 mikedld 1007
	call	queue
261 hidnplayr 1008
 
907 mikedld 1009
	mov	esi, [sockAddr]
261 hidnplayr 1010
 
907 mikedld 1011
	; increament SND.NXT in socket
1012
	; Amount to increment by is in ecx
1013
	add	esi, SOCKET.SND_NXT
1014
	call	add_inet_esi
261 hidnplayr 1015
 
907 mikedld 1016
	pop	ebx
261 hidnplayr 1017
 
907 mikedld 1018
	; Copy the IP buffer to a resend queue
1019
	; If there isn't one, dont worry about it for now
1020
	mov	esi, resendQ
1021
	mov	ecx, 0
261 hidnplayr 1022
 
907 mikedld 1023
  .next_resendq:
1024
	cmp	ecx, NUMRESENDENTRIES
1025
	je	.exit		   ; None found
1026
	;cmp     byte[esi], 0xff                                 ; XTODO: 0xff -> 0
1027
	cmp	dword[esi + 4], 0
1028
	je	@f		   ; found one
1029
	inc	ecx
1030
	add	esi, 8
1031
	jmp	.next_resendq
261 hidnplayr 1032
 
907 mikedld 1033
    @@: push	ebx
261 hidnplayr 1034
 
907 mikedld 1035
	; OK, we have a buffer descriptor ptr in esi.
1036
	; resend entry # in ecx
1037
	;  Populate it
1038
	;  socket #
1039
	;  retries count
1040
	;  retry time
1041
	;  fill IP buffer associated with this descriptor
261 hidnplayr 1042
 
907 mikedld 1043
	stdcall net_socket_addr_to_num, [sockAddr]
1044
	;mov     [esi], al                               ; XTODO: al -> eax
1045
	mov	[esi + 4], eax
1046
	mov	byte[esi + 1], TCP_RETRIES
1047
	mov	word[esi + 2], TCP_TIMEOUT
261 hidnplayr 1048
 
907 mikedld 1049
	inc	ecx
1050
	; Now get buffer location, and copy buffer across. argh! more copying,,
1051
	mov	edi, resendBuffer - IPBUFFSIZE
261 hidnplayr 1052
 
907 mikedld 1053
    @@: add	edi, IPBUFFSIZE
1054
	loop	@b
261 hidnplayr 1055
 
907 mikedld 1056
	; we have dest buffer location in edi
1057
	pop	eax
1058
	; convert source buffer pointer eax to the absolute address
1059
	mov	ecx, IPBUFFSIZE
1060
	mul	ecx
1061
	add	eax, IPbuffs
1062
	mov	esi, eax
261 hidnplayr 1063
 
907 mikedld 1064
	; do copy
1065
	mov	ecx, IPBUFFSIZE
1066
	cld
1067
	rep	movsb
261 hidnplayr 1068
 
907 mikedld 1069
  .exit:
1070
	xor	eax, eax
1071
	ret
261 hidnplayr 1072
 
907 mikedld 1073
  .error:
1074
	or	eax, -1
1075
	ret
1076
endp