Subversion Repositories Kolibri OS

Rev

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

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