Subversion Repositories Kolibri OS

Rev

Rev 914 | Details | Compare with Previous | Last modification | View Log | RSS feed

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