Subversion Repositories Kolibri OS

Rev

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

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