Subversion Repositories Kolibri OS

Rev

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

Rev Author Line No. Line
3545 hidnplayr 1
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
2
;;                                                                 ;;
5363 yogev_ezra 3
;; Copyright (C) KolibriOS team 2004-2015. All rights reserved.    ;;
3545 hidnplayr 4
;; Distributed under terms of the GNU General Public License       ;;
5
;;                                                                 ;;
6
;;  Part of the TCP/IP network stack for KolibriOS                 ;;
7
;;                                                                 ;;
8
;;   Written by hidnplayr@kolibrios.org,                           ;;
9
;;     and Clevermouse.                                            ;;
10
;;                                                                 ;;
11
;;       Based on code by mike.dld                                 ;;
12
;;                                                                 ;;
13
;;         GNU GENERAL PUBLIC LICENSE                              ;;
14
;;          Version 2, June 1991                                   ;;
15
;;                                                                 ;;
16
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
17
 
4850 mario79 18
$Revision: 5842 $
3545 hidnplayr 19
 
20
struct  SOCKET
21
 
22
        NextPtr                 dd ? ; pointer to next socket in list
23
        PrevPtr                 dd ? ; pointer to previous socket in list
24
        Number                  dd ? ; socket number
25
 
26
        mutex                   MUTEX
27
 
28
        PID                     dd ? ; process ID
29
        TID                     dd ? ; thread ID
5842 hidnplayr 30
        Domain                  dd ? ; INET4/INET6/LOCAL/..
4365 hidnplayr 31
        Type                    dd ? ; RAW/STREAM/DGRAM
5842 hidnplayr 32
        Protocol                dd ? ; UDP/TCP/ARP/ICMP
3545 hidnplayr 33
        errorcode               dd ?
34
        device                  dd ? ; driver pointer, socket pointer if it's an LOCAL socket
35
 
36
        options                 dd ?
37
        state                   dd ?
38
        backlog                 dw ? ; how many incoming connections that can be queued
39
 
40
        snd_proc                dd ?
41
        rcv_proc                dd ?
4030 hidnplayr 42
        connect_proc            dd ?
3545 hidnplayr 43
 
44
ends
45
 
46
struct  IP_SOCKET               SOCKET
47
 
48
        LocalIP                 rd 4 ; network byte order
49
        RemoteIP                rd 4 ; network byte order
5842 hidnplayr 50
        ttl                     db ?
51
                                rb 3 ; align
3545 hidnplayr 52
 
53
ends
54
 
55
struct  TCP_SOCKET              IP_SOCKET
56
 
57
        LocalPort               dw ? ; network byte order
58
        RemotePort              dw ? ; network byte order
59
 
60
        t_state                 dd ? ; TCB state
61
        t_rxtshift              db ?
62
                                rb 3 ; align
63
        t_rxtcur                dd ?
64
        t_dupacks               dd ?
65
        t_maxseg                dd ?
66
        t_force                 dd ?
67
        t_flags                 dd ?
68
 
69
;---------------
70
; RFC783 page 21
71
 
72
; send sequence
73
        SND_UNA                 dd ? ; sequence number of unack'ed sent Packets
74
        SND_NXT                 dd ? ; next send sequence number to use
75
        SND_UP                  dd ? ; urgent pointer
76
        SND_WL1                 dd ? ; window minus one
77
        SND_WL2                 dd ? ;
78
        ISS                     dd ? ; initial send sequence number
79
        SND_WND                 dd ? ; send window
80
 
81
; receive sequence
82
        RCV_WND                 dd ? ; receive window
83
        RCV_NXT                 dd ? ; next receive sequence number to use
84
        RCV_UP                  dd ? ; urgent pointer
85
        IRS                     dd ? ; initial receive sequence number
86
 
87
;---------------------
88
; Additional variables
89
 
90
; receive variables
91
        RCV_ADV                 dd ?
92
 
93
; retransmit variables
94
        SND_MAX                 dd ?
95
 
96
; congestion control
4339 hidnplayr 97
        SND_CWND                dd ?    ; congestion window
98
        SND_SSTHRESH            dd ?    ; slow start threshold
3545 hidnplayr 99
 
100
;----------------------
101
; Transmit timing stuff
102
        t_idle                  dd ?
5442 hidnplayr 103
        t_rtt                   dd ?    ; round trip time
3545 hidnplayr 104
        t_rtseq                 dd ?
5442 hidnplayr 105
        t_srtt                  dd ?    ; smoothed round trip time
3545 hidnplayr 106
        t_rttvar                dd ?
107
        t_rttmin                dd ?
108
        max_sndwnd              dd ?
109
 
110
;-----------------
111
; Out-of-band data
112
        t_oobflags              dd ?
113
        t_iobc                  dd ?
114
        t_softerror             dd ?
115
 
116
 
117
;---------
118
; RFC 1323                              ; the order of next 4 elements may not change
119
 
120
        SND_SCALE               db ?
121
        RCV_SCALE               db ?
122
        requested_s_scale       db ?
123
        request_r_scale         db ?
124
 
125
        ts_recent               dd ?    ; a copy of the most-recent valid timestamp from the other end
126
        ts_recent_age           dd ?
127
        last_ack_sent           dd ?
128
 
129
 
130
;-------
131
; Timers
3600 hidnplayr 132
        timer_flags             dd ?
3545 hidnplayr 133
        timer_retransmission    dd ? ; rexmt
134
        timer_persist           dd ?
135
        timer_keepalive         dd ? ; keepalive/syn timeout
136
        timer_timed_wait        dd ? ; also used as 2msl timer
4021 hidnplayr 137
        timer_connect           dd ?
3545 hidnplayr 138
 
139
; extra
140
 
141
        ts_ecr                  dd ? ; timestamp echo reply
142
        ts_val                  dd ?
143
 
144
        seg_next                dd ? ; re-assembly queue
145
 
146
ends
147
 
148
struct  UDP_SOCKET              IP_SOCKET
149
 
150
        LocalPort               dw ? ; network byte order
151
        RemotePort              dw ? ; network byte order
152
 
153
ends
154
 
155
struct  RING_BUFFER
156
 
157
        mutex                   MUTEX
158
        start_ptr               dd ? ; Pointer to start of buffer
159
        end_ptr                 dd ? ; pointer to end of buffer
160
        read_ptr                dd ? ; Read pointer
161
        write_ptr               dd ? ; Write pointer
162
        size                    dd ? ; Number of bytes buffered
163
 
164
ends
165
 
166
struct  STREAM_SOCKET           TCP_SOCKET
167
 
168
        rcv                     RING_BUFFER
169
        snd                     RING_BUFFER
170
 
171
ends
172
 
173
struct  socket_queue_entry
174
 
175
        data_ptr                dd ?
5522 hidnplayr 176
        data_size               dd ?
3545 hidnplayr 177
        buf_ptr                 dd ?
178
 
179
ends
180
 
181
 
182
SOCKETBUFFSIZE          = 4096     ; in bytes
183
 
184
SOCKET_QUEUE_SIZE       = 10       ; maximum number of incoming packets queued for 1 socket
185
; the incoming packet queue for sockets is placed in the socket struct itself, at this location from start
186
SOCKET_QUEUE_LOCATION   = (SOCKETBUFFSIZE - SOCKET_QUEUE_SIZE*sizeof.socket_queue_entry - sizeof.queue)
187
 
188
uglobal
3698 hidnplayr 189
align 4
190
 
3545 hidnplayr 191
        net_sockets     rd 4
192
        last_socket_num dd ?
193
        last_UDP_port   dw ? ; These values give the number of the last used ephemeral port
194
        last_TCP_port   dw ? ;
3647 hidnplayr 195
        socket_mutex    MUTEX
3698 hidnplayr 196
 
3545 hidnplayr 197
endg
198
 
199
 
200
;-----------------------------------------------------------------
201
;
202
; SOCKET_init
203
;
204
;-----------------------------------------------------------------
205
macro   SOCKET_init {
206
 
207
        xor     eax, eax
208
        mov     edi, net_sockets
209
        mov     ecx, 5
3711 clevermous 210
        rep stosd
3545 hidnplayr 211
 
212
       @@:
213
        pseudo_random eax
3600 hidnplayr 214
        cmp     ax, EPHEMERAL_PORT_MIN
3545 hidnplayr 215
        jb      @r
3600 hidnplayr 216
        cmp     ax, EPHEMERAL_PORT_MAX
3545 hidnplayr 217
        ja      @r
218
        xchg    al, ah
219
        mov     [last_UDP_port], ax
220
 
221
       @@:
222
        pseudo_random eax
3600 hidnplayr 223
        cmp     ax, EPHEMERAL_PORT_MIN
3545 hidnplayr 224
        jb      @r
3600 hidnplayr 225
        cmp     ax, EPHEMERAL_PORT_MAX
3545 hidnplayr 226
        ja      @r
227
        xchg    al, ah
228
        mov     [last_TCP_port], ax
229
 
3647 hidnplayr 230
        mov     ecx, socket_mutex
231
        call    mutex_init
232
 
3545 hidnplayr 233
}
234
 
235
;-----------------------------------------------------------------
236
;
237
; Socket API (function 74)
238
;
239
;-----------------------------------------------------------------
240
align 4
241
sys_socket:
242
 
3673 hidnplayr 243
        mov     dword[esp+20], 0        ; Set error code to 0
3659 hidnplayr 244
 
3545 hidnplayr 245
        cmp     ebx, 255
246
        jz      SOCKET_debug
247
 
248
        cmp     ebx, .number
3658 hidnplayr 249
        ja      .error
3545 hidnplayr 250
        jmp     dword [.table + 4*ebx]
251
 
252
  .table:
253
        dd      SOCKET_open     ; 0
254
        dd      SOCKET_close    ; 1
255
        dd      SOCKET_bind     ; 2
256
        dd      SOCKET_listen   ; 3
257
        dd      SOCKET_connect  ; 4
258
        dd      SOCKET_accept   ; 5
259
        dd      SOCKET_send     ; 6
260
        dd      SOCKET_receive  ; 7
261
        dd      SOCKET_set_opt  ; 8
262
        dd      SOCKET_get_opt  ; 9
263
        dd      SOCKET_pair     ; 10
264
  .number = ($ - .table) / 4 - 1
265
 
3658 hidnplayr 266
  .error:
267
        mov     dword[esp+32], -1
3673 hidnplayr 268
        mov     dword[esp+20], EINVAL
3545 hidnplayr 269
 
270
        ret
271
 
272
;-----------------------------------------------------------------
273
;
274
; SOCKET_open
275
;
276
;  IN:  domain in ecx
277
;       type in edx
278
;       protocol in esi
279
;  OUT: eax is socket num, -1 on error
280
;
281
;-----------------------------------------------------------------
282
align 4
283
SOCKET_open:
284
 
3556 hidnplayr 285
        DEBUGF  DEBUG_NETWORK_VERBOSE, "SOCKET_open: domain=%u type=%u protocol=%x ", ecx, edx, esi
3545 hidnplayr 286
 
287
        push    ecx edx esi
288
        call    SOCKET_alloc
289
        pop     esi edx ecx
4535 hidnplayr 290
        test    eax, eax
3658 hidnplayr 291
        jz      .nobuffs
3545 hidnplayr 292
 
293
        mov     [esp+32], edi                   ; return socketnumber
3556 hidnplayr 294
        DEBUGF  DEBUG_NETWORK_VERBOSE, "socknum=%u\n", edi
3545 hidnplayr 295
 
3705 hidnplayr 296
        test    edx, SO_NONBLOCK
297
        jz      @f
298
        or      [eax + SOCKET.options], SO_NONBLOCK
299
        and     edx, not SO_NONBLOCK
300
  @@:
3545 hidnplayr 301
 
302
        mov     [eax + SOCKET.Domain], ecx
303
        mov     [eax + SOCKET.Type], edx
304
        mov     [eax + SOCKET.Protocol], esi
4030 hidnplayr 305
        mov     [eax + SOCKET.connect_proc], connect_notsupp
3545 hidnplayr 306
 
307
        cmp     ecx, AF_INET4
308
        jne     .no_inet4
309
 
5842 hidnplayr 310
        mov     [eax + IP_SOCKET.ttl], 128
311
 
3545 hidnplayr 312
        cmp     edx, SOCK_DGRAM
313
        je      .udp
314
 
315
        cmp     edx, SOCK_STREAM
316
        je      .tcp
317
 
318
        cmp     edx, SOCK_RAW
319
        je      .raw
320
 
321
  .no_inet4:
322
        cmp     ecx, AF_PPP
323
        jne     .no_ppp
324
 
325
        cmp     esi, PPP_PROTO_ETHERNET
326
        je      .pppoe
327
 
328
  .no_ppp:
3658 hidnplayr 329
  .unsupported:
330
        push    eax
331
        call    SOCKET_free
332
        pop     eax
3673 hidnplayr 333
        mov     dword[esp+20], EOPNOTSUPP
3658 hidnplayr 334
        mov     dword[esp+32], -1
3545 hidnplayr 335
        ret
336
 
3658 hidnplayr 337
  .nobuffs:
3673 hidnplayr 338
        mov     dword[esp+20], ENOBUFS
3658 hidnplayr 339
        mov     dword[esp+32], -1
340
        ret
341
 
3545 hidnplayr 342
  .raw:
343
        test    esi, esi       ; IP_PROTO_IP
3658 hidnplayr 344
        jz      .raw_ip
3545 hidnplayr 345
 
346
        cmp     esi, IP_PROTO_ICMP
3658 hidnplayr 347
        je      .raw_icmp
3545 hidnplayr 348
 
3658 hidnplayr 349
        jmp     .unsupported
3545 hidnplayr 350
 
351
align 4
352
  .udp:
5842 hidnplayr 353
        push    eax
354
        init_queue (eax + SOCKET_QUEUE_LOCATION)        ; Set up data receiving queue
355
        pop     eax
356
 
3545 hidnplayr 357
        mov     [eax + SOCKET.Protocol], IP_PROTO_UDP
358
        mov     [eax + SOCKET.snd_proc], SOCKET_send_udp
359
        mov     [eax + SOCKET.rcv_proc], SOCKET_receive_dgram
4030 hidnplayr 360
        mov     [eax + SOCKET.connect_proc], UDP_connect
3545 hidnplayr 361
        ret
362
 
363
align 4
364
  .tcp:
365
        mov     [eax + SOCKET.Protocol], IP_PROTO_TCP
366
        mov     [eax + SOCKET.snd_proc], SOCKET_send_tcp
367
        mov     [eax + SOCKET.rcv_proc], SOCKET_receive_stream
4030 hidnplayr 368
        mov     [eax + SOCKET.connect_proc], TCP_connect
3545 hidnplayr 369
 
370
        TCP_init_socket eax
371
        ret
372
 
373
 
374
align 4
3658 hidnplayr 375
  .raw_ip:
5842 hidnplayr 376
        push    eax
377
        init_queue (eax + SOCKET_QUEUE_LOCATION)        ; Set up data receiving queue
378
        pop     eax
379
 
3545 hidnplayr 380
        mov     [eax + SOCKET.snd_proc], SOCKET_send_ip
381
        mov     [eax + SOCKET.rcv_proc], SOCKET_receive_dgram
4030 hidnplayr 382
        mov     [eax + SOCKET.connect_proc], IPv4_connect
3545 hidnplayr 383
        ret
384
 
385
 
386
align 4
3658 hidnplayr 387
  .raw_icmp:
5842 hidnplayr 388
        push    eax
389
        init_queue (eax + SOCKET_QUEUE_LOCATION)        ; Set up data receiving queue
390
        pop     eax
391
 
3545 hidnplayr 392
        mov     [eax + SOCKET.snd_proc], SOCKET_send_icmp
393
        mov     [eax + SOCKET.rcv_proc], SOCKET_receive_dgram
4030 hidnplayr 394
        mov     [eax + SOCKET.connect_proc], IPv4_connect
3545 hidnplayr 395
        ret
396
 
397
align 4
398
  .pppoe:
399
        push    eax
400
        init_queue (eax + SOCKET_QUEUE_LOCATION)        ; Set up data receiving queue
401
        pop     eax
402
 
403
        mov     [eax + SOCKET.snd_proc], SOCKET_send_pppoe
404
        mov     [eax + SOCKET.rcv_proc], SOCKET_receive_dgram
405
        ret
406
 
407
 
408
;-----------------------------------------------------------------
409
;
410
; SOCKET_bind
411
;
412
;  IN:  socket number in ecx
413
;       pointer to sockaddr struct in edx
414
;       length of that struct in esi
415
;  OUT: 0 on success
416
;
417
;-----------------------------------------------------------------
418
align 4
419
SOCKET_bind:
420
 
3556 hidnplayr 421
        DEBUGF  DEBUG_NETWORK_VERBOSE, "SOCKET_bind: socknum=%u sockaddr=%x length=%u\n", ecx, edx, esi
3545 hidnplayr 422
 
423
        call    SOCKET_num_to_ptr
3658 hidnplayr 424
        jz      .invalid
3545 hidnplayr 425
 
426
        cmp     esi, 2
3658 hidnplayr 427
        jb      .invalid
3545 hidnplayr 428
 
4052 hidnplayr 429
        cmp     [eax + UDP_SOCKET.LocalPort], 0         ; Socket can only be bound once
430
        jnz     .invalid
431
 
3545 hidnplayr 432
        cmp     word [edx], AF_INET4
433
        je      .af_inet4
434
 
435
        cmp     word [edx], AF_LOCAL
436
        je      .af_local
437
 
3658 hidnplayr 438
  .notsupp:
3673 hidnplayr 439
        mov     dword[esp+20], EOPNOTSUPP
3658 hidnplayr 440
        mov     dword[esp+32], -1
441
        ret
3545 hidnplayr 442
 
3658 hidnplayr 443
  .invalid:
3673 hidnplayr 444
        mov     dword[esp+20], EINVAL
3658 hidnplayr 445
        mov     dword[esp+32], -1
446
        ret
447
 
3545 hidnplayr 448
  .af_local:
449
        ; TODO: write code here
3658 hidnplayr 450
        mov     dword[esp+32], 0
3545 hidnplayr 451
        ret
452
 
453
  .af_inet4:
454
        cmp     esi, 6
3658 hidnplayr 455
        jb      .invalid
3545 hidnplayr 456
 
457
        cmp     [eax + SOCKET.Protocol], IP_PROTO_UDP
458
        je      .udp
459
 
460
        cmp     [eax + SOCKET.Protocol], IP_PROTO_TCP
461
        je      .tcp
462
 
3658 hidnplayr 463
        jmp     .notsupp
3545 hidnplayr 464
 
465
  .tcp:
466
  .udp:
467
 
4052 hidnplayr 468
        pushd   [edx + 4]                       ; First, fill in the IP
469
        popd    [eax + IP_SOCKET.LocalIP]
3545 hidnplayr 470
 
4052 hidnplayr 471
        mov     bx, [edx + 2]                   ; Did caller specify a local port?
472
        test    bx, bx
473
        jnz     .just_check
474
        call    SOCKET_find_port                ; Nope, find an ephemeral one
475
        jmp     .done
476
 
477
  .just_check:
478
        call    SOCKET_check_port               ; Yes, check if it's still available
479
        jz      .addrinuse                      ; ZF is set by socket_check_port on error
480
 
481
  .done:
3556 hidnplayr 482
        DEBUGF  DEBUG_NETWORK_VERBOSE, "SOCKET_bind: local ip=%u.%u.%u.%u\n",\
3545 hidnplayr 483
        [eax + IP_SOCKET.LocalIP + 0]:1,[eax + IP_SOCKET.LocalIP + 1]:1,\
484
        [eax + IP_SOCKET.LocalIP + 2]:1,[eax + IP_SOCKET.LocalIP + 3]:1
485
 
3658 hidnplayr 486
        mov     dword[esp+32], 0
3545 hidnplayr 487
        ret
488
 
3658 hidnplayr 489
  .addrinuse:
490
        mov     dword[esp+32], -1
3673 hidnplayr 491
        mov     dword[esp+20], EADDRINUSE
3658 hidnplayr 492
        ret
3545 hidnplayr 493
 
494
 
495
 
3658 hidnplayr 496
 
3545 hidnplayr 497
;-----------------------------------------------------------------
498
;
499
; SOCKET_connect
500
;
501
;  IN:  socket number in ecx
502
;       pointer to sockaddr struct in edx
503
;       length of that struct in esi
504
;  OUT: 0 on success
505
;
506
;-----------------------------------------------------------------
507
align 4
508
SOCKET_connect:
509
 
3556 hidnplayr 510
        DEBUGF  DEBUG_NETWORK_VERBOSE, "SOCKET_connect: socknum=%u sockaddr=%x length=%u\n", ecx, edx, esi
3545 hidnplayr 511
 
512
        call    SOCKET_num_to_ptr
3658 hidnplayr 513
        jz      .invalid
3545 hidnplayr 514
 
515
        cmp     esi, 8
3658 hidnplayr 516
        jb      .invalid
3545 hidnplayr 517
 
4025 hidnplayr 518
        cmp     [eax + SOCKET.state], SS_ISCONNECTING
519
        je      .already
520
 
521
        test    [eax + SOCKET.options], SO_ACCEPTCON
522
        jnz     .notsupp
523
 
4030 hidnplayr 524
        call    [eax + SOCKET.connect_proc]
3545 hidnplayr 525
 
4030 hidnplayr 526
        mov     dword[esp+20], ebx
527
        mov     dword[esp+32], eax
528
        ret
529
 
530
 
3658 hidnplayr 531
  .notsupp:
3673 hidnplayr 532
        mov     dword[esp+20], EOPNOTSUPP
3658 hidnplayr 533
        mov     dword[esp+32], -1
534
        ret
3545 hidnplayr 535
 
3658 hidnplayr 536
  .invalid:
3673 hidnplayr 537
        mov     dword[esp+20], EINVAL
3658 hidnplayr 538
        mov     dword[esp+32], -1
539
        ret
540
 
4025 hidnplayr 541
  .already:
542
        mov     dword[esp+20], EALREADY
543
        mov     dword[esp+32], -1
544
        ret
545
 
546
 
4030 hidnplayr 547
connect_notsupp:
548
        xor     eax, eax
549
        dec     eax
550
        mov     ebx, EOPNOTSUPP
3545 hidnplayr 551
        ret
552
 
4025 hidnplayr 553
 
3545 hidnplayr 554
;-----------------------------------------------------------------
555
;
556
; SOCKET_listen
557
;
558
;  IN:  socket number in ecx
559
;       backlog in edx
560
;  OUT: eax is socket num, -1 on error
561
;
562
;-----------------------------------------------------------------
563
align 4
564
SOCKET_listen:
565
 
3556 hidnplayr 566
        DEBUGF  DEBUG_NETWORK_VERBOSE, "SOCKET_listen: socknum=%u backlog=%u\n", ecx, edx
3545 hidnplayr 567
 
568
        call    SOCKET_num_to_ptr
3658 hidnplayr 569
        jz      .invalid
3545 hidnplayr 570
 
571
        cmp     [eax + SOCKET.Domain], AF_INET4
3658 hidnplayr 572
        jne     .notsupp
3545 hidnplayr 573
 
574
        cmp     [eax + SOCKET.Protocol], IP_PROTO_TCP
3658 hidnplayr 575
        jne     .invalid
3545 hidnplayr 576
 
577
        cmp     [eax + TCP_SOCKET.LocalPort], 0
3658 hidnplayr 578
        je      .already
3545 hidnplayr 579
 
580
        cmp     [eax + IP_SOCKET.LocalIP], 0
581
        jne     @f
3601 hidnplayr 582
        push    [IP_LIST + 4]           ;;; fixme!!!!
3545 hidnplayr 583
        pop     [eax + IP_SOCKET.LocalIP]
584
       @@:
585
 
586
        cmp     edx, MAX_backlog
587
        jbe     @f
588
        mov     edx, MAX_backlog
589
       @@:
590
 
591
        mov     [eax + SOCKET.backlog], dx
592
        or      [eax + SOCKET.options], SO_ACCEPTCON
593
        mov     [eax + TCP_SOCKET.t_state], TCPS_LISTEN
594
        mov     [eax + TCP_SOCKET.timer_keepalive], 0           ; disable keepalive timer
595
 
596
        push    eax
597
        init_queue (eax + SOCKET_QUEUE_LOCATION)                ; Set up sockets queue
598
        pop     eax
599
 
3658 hidnplayr 600
        mov     dword[esp+32], 0
601
        ret
3545 hidnplayr 602
 
3658 hidnplayr 603
  .notsupp:
3673 hidnplayr 604
        mov     dword[esp+20], EOPNOTSUPP
3658 hidnplayr 605
        mov     dword[esp+32], -1
3545 hidnplayr 606
        ret
607
 
3658 hidnplayr 608
  .invalid:
3673 hidnplayr 609
        mov     dword[esp+20], EINVAL
3658 hidnplayr 610
        mov     dword[esp+32], -1
611
        ret
3545 hidnplayr 612
 
3658 hidnplayr 613
  .already:
3673 hidnplayr 614
        mov     dword[esp+20], EALREADY
3658 hidnplayr 615
        mov     dword[esp+32], -1
616
        ret
617
 
618
 
3545 hidnplayr 619
;-----------------------------------------------------------------
620
;
621
; SOCKET_accept
622
;
623
;  IN:  socket number in ecx
624
;       addr in edx
625
;       addrlen in esi
626
;  OUT: eax is socket num, -1 on error
627
;
628
;-----------------------------------------------------------------
629
align 4
630
SOCKET_accept:
631
 
3556 hidnplayr 632
        DEBUGF  DEBUG_NETWORK_VERBOSE, "SOCKET_accept: socknum=%u sockaddr=%x length=%u\n", ecx, edx, esi
3545 hidnplayr 633
 
634
        call    SOCKET_num_to_ptr
3658 hidnplayr 635
        jz      .invalid
3545 hidnplayr 636
 
637
        test    [eax + SOCKET.options], SO_ACCEPTCON
3658 hidnplayr 638
        jz      .invalid
3545 hidnplayr 639
 
640
        cmp     [eax + SOCKET.Domain], AF_INET4
3658 hidnplayr 641
        jne     .notsupp
3545 hidnplayr 642
 
643
        cmp     [eax + SOCKET.Protocol], IP_PROTO_TCP
3658 hidnplayr 644
        jne     .invalid
3545 hidnplayr 645
 
646
  .loop:
647
        get_from_queue (eax + SOCKET_QUEUE_LOCATION), MAX_backlog, 4, .block
648
 
649
; Ok, we got a socket ptr
650
        mov     eax, [esi]
651
 
652
; Change thread ID to that of the current thread
653
        mov     ebx, [TASK_BASE]
654
        mov     ebx, [ebx + TASKDATA.pid]
655
        mov     [eax + SOCKET.TID], ebx
656
 
3817 hidnplayr 657
; Convert it to a socket number
658
        call    SOCKET_ptr_to_num
659
        jz      .invalid        ; FIXME ?
660
 
3545 hidnplayr 661
; and return it to caller
662
        mov     [esp+32], eax
663
        ret
664
 
665
  .block:
666
        test    [eax + SOCKET.options], SO_NONBLOCK
3658 hidnplayr 667
        jnz     .wouldblock
3545 hidnplayr 668
 
669
        call    SOCKET_block
670
        jmp     .loop
671
 
3658 hidnplayr 672
  .wouldblock:
3673 hidnplayr 673
        mov     dword[esp+20], EWOULDBLOCK
3658 hidnplayr 674
        mov     dword[esp+32], -1
675
        ret
676
 
677
  .invalid:
3673 hidnplayr 678
        mov     dword[esp+20], EINVAL
3658 hidnplayr 679
        mov     dword[esp+32], -1
680
        ret
681
 
682
  .notsupp:
3673 hidnplayr 683
        mov     dword[esp+20], EOPNOTSUPP
3658 hidnplayr 684
        mov     dword[esp+32], -1
685
        ret
686
 
3545 hidnplayr 687
;-----------------------------------------------------------------
688
;
689
; SOCKET_close
690
;
691
;  IN:  socket number in ecx
692
;  OUT: eax is socket num, -1 on error
693
;
694
;-----------------------------------------------------------------
695
align 4
696
SOCKET_close:
697
 
3556 hidnplayr 698
        DEBUGF  DEBUG_NETWORK_VERBOSE, "SOCKET_close: socknum=%u\n", ecx
3545 hidnplayr 699
 
700
        call    SOCKET_num_to_ptr
3658 hidnplayr 701
        jz      .invalid
3545 hidnplayr 702
 
3658 hidnplayr 703
        mov     dword[esp+32], 0                                ; The socket exists, so we will succeed in closing it.
3545 hidnplayr 704
 
705
        or      [eax + SOCKET.options], SO_NONBLOCK             ; Mark the socket as non blocking, we dont want it to block any longer!
706
 
707
        test    [eax + SOCKET.state], SS_BLOCKED                ; Is the socket still in blocked state?
708
        jz      @f
4528 hidnplayr 709
        call    SOCKET_notify                                   ; Unblock it.
3545 hidnplayr 710
  @@:
711
 
712
        cmp     [eax + SOCKET.Domain], AF_INET4
713
        jne     .free
714
 
715
        cmp     [eax + SOCKET.Protocol], IP_PROTO_TCP
716
        je      .tcp
717
 
718
  .free:
719
        call    SOCKET_free
720
        ret
721
 
722
  .tcp:
723
 
724
        call    TCP_usrclosed
725
 
4366 hidnplayr 726
        test    eax, eax
727
        jz      @f
728
        call    TCP_output                                      ; If connection is not closed yet, send the FIN
729
  @@:
730
 
3545 hidnplayr 731
        ret
732
 
733
 
3658 hidnplayr 734
  .invalid:
3673 hidnplayr 735
        mov     dword[esp+20], EINVAL
3658 hidnplayr 736
        mov     dword[esp+32], -1
737
        ret
738
 
739
 
3545 hidnplayr 740
;-----------------------------------------------------------------
741
;
742
; SOCKET_receive
743
;
744
;  IN:  socket number in ecx
745
;       addr to buffer in edx
746
;       length of buffer in esi
747
;       flags in edi
748
;  OUT: eax is number of bytes copied, -1 on error
749
;
750
;-----------------------------------------------------------------
751
align 4
752
SOCKET_receive:
753
 
3556 hidnplayr 754
        DEBUGF  DEBUG_NETWORK_VERBOSE, "SOCKET_receive: socknum=%u bufaddr=%x buflength=%u flags=%x\n", ecx, edx, esi, edi
3545 hidnplayr 755
 
756
        call    SOCKET_num_to_ptr
3658 hidnplayr 757
        jz      .invalid
3545 hidnplayr 758
 
3704 hidnplayr 759
  .loop:
760
        push    edi
3565 hidnplayr 761
        call    [eax + SOCKET.rcv_proc]
3704 hidnplayr 762
        pop     edi
3545 hidnplayr 763
 
4219 hidnplayr 764
        test    [eax + SOCKET.state], SS_CANTRCVMORE
5364 hidnplayr 765
        jnz     .last_data
4219 hidnplayr 766
 
3704 hidnplayr 767
        cmp     ebx, EWOULDBLOCK
768
        jne     .return
769
 
770
        test    edi, MSG_DONTWAIT
771
        jnz     .return_err
772
 
773
;        test    [eax + SOCKET.options], SO_NONBLOCK
774
;        jnz     .return_err
775
 
776
        call    SOCKET_block
777
        jmp     .loop
778
 
779
 
780
  .invalid:
781
        push    EINVAL
782
        pop     ebx
783
  .return_err:
4219 hidnplayr 784
        mov     ecx, -1
3704 hidnplayr 785
  .return:
3673 hidnplayr 786
        mov     [esp+20], ebx
4219 hidnplayr 787
        mov     [esp+32], ecx
3565 hidnplayr 788
        ret
3545 hidnplayr 789
 
5364 hidnplayr 790
  .last_data:
791
        test    ecx, ecx
792
        jz      .return
793
        call    SOCKET_notify
794
        jmp     .return
3565 hidnplayr 795
 
3658 hidnplayr 796
 
3704 hidnplayr 797
 
798
 
3545 hidnplayr 799
align 4
800
SOCKET_receive_dgram:
3704 hidnplayr 801
 
3556 hidnplayr 802
        DEBUGF  DEBUG_NETWORK_VERBOSE, "SOCKET_receive: DGRAM\n"
3545 hidnplayr 803
 
3704 hidnplayr 804
        mov     ebx, esi                                        ; bufferlength
3545 hidnplayr 805
 
3704 hidnplayr 806
        get_from_queue (eax + SOCKET_QUEUE_LOCATION), SOCKET_QUEUE_SIZE, sizeof.socket_queue_entry, .wouldblock ; sets esi only on success.
3545 hidnplayr 807
        mov     ecx, [esi + socket_queue_entry.data_size]
3556 hidnplayr 808
        DEBUGF  DEBUG_NETWORK_VERBOSE, "SOCKET_receive: %u bytes data\n", ecx
3545 hidnplayr 809
 
3704 hidnplayr 810
        cmp     ecx, ebx                                        ; If data segment does not fit in applications buffer, abort
3545 hidnplayr 811
        ja      .too_small
812
 
4219 hidnplayr 813
        push    eax ecx
3545 hidnplayr 814
        push    [esi + socket_queue_entry.buf_ptr]              ; save the buffer addr so we can clear it later
815
        mov     esi, [esi + socket_queue_entry.data_ptr]
3556 hidnplayr 816
        DEBUGF  DEBUG_NETWORK_VERBOSE, "SOCKET_receive: Source buffer=%x real addr=%x\n", [esp], esi
3545 hidnplayr 817
 
3704 hidnplayr 818
; copy the data from kernel buffer to application buffer
819
        mov     edi, edx                                        ; bufferaddr
3545 hidnplayr 820
        shr     ecx, 1
821
        jnc     .nb
822
        movsb
823
  .nb:
824
        shr     ecx, 1
825
        jnc     .nw
826
        movsw
827
  .nw:
828
        test    ecx, ecx
829
        jz      .nd
3711 clevermous 830
        rep movsd
3545 hidnplayr 831
  .nd:
832
 
5522 hidnplayr 833
        call    NET_BUFF_free
4219 hidnplayr 834
        pop     ecx eax                                         ; return number of bytes copied to application
3704 hidnplayr 835
        xor     ebx, ebx
3545 hidnplayr 836
        ret
837
 
838
  .too_small:
4219 hidnplayr 839
        mov     ecx, -1
3704 hidnplayr 840
        push    EMSGSIZE
841
        pop     ebx
3565 hidnplayr 842
        ret
3545 hidnplayr 843
 
3658 hidnplayr 844
  .wouldblock:
3704 hidnplayr 845
        push    EWOULDBLOCK
846
        pop     ebx
3658 hidnplayr 847
        ret
3545 hidnplayr 848
 
3658 hidnplayr 849
 
3704 hidnplayr 850
 
3545 hidnplayr 851
align 4
852
SOCKET_receive_local:
853
 
854
        ; does this socket have a PID yet?
855
        cmp     [eax + SOCKET.PID], 0
856
        jne     @f
857
 
858
        ; Change PID to that of current process
859
        mov     ebx, [TASK_BASE]
860
        mov     ebx, [ebx + TASKDATA.pid]
861
        mov     [eax + SOCKET.PID], ebx
3704 hidnplayr 862
        mov     [eax + SOCKET.TID], ebx                         ; currently TID = PID in kolibrios :(
3545 hidnplayr 863
      @@:
864
 
865
        mov     [eax + SOCKET.rcv_proc], SOCKET_receive_stream
866
 
3704 hidnplayr 867
; ... continue to SOCKET_receive_stream
868
 
3545 hidnplayr 869
align 4
870
SOCKET_receive_stream:
871
 
3556 hidnplayr 872
        DEBUGF  DEBUG_NETWORK_VERBOSE, "SOCKET_receive: STREAM\n"
3545 hidnplayr 873
 
3704 hidnplayr 874
        cmp     [eax + STREAM_SOCKET.rcv + RING_BUFFER.size], 0
875
        je      .wouldblock
876
 
877
        test    edi, MSG_PEEK
878
        jnz     .peek
879
 
3545 hidnplayr 880
        mov     ecx, esi
881
        mov     edi, edx
882
        xor     edx, edx
883
 
4219 hidnplayr 884
        push    eax
3545 hidnplayr 885
        add     eax, STREAM_SOCKET.rcv
3704 hidnplayr 886
        call    SOCKET_ring_read                                ; copy data from kernel buffer to application buffer
887
        call    SOCKET_ring_free                                ; free read memory
4219 hidnplayr 888
        pop     eax
3545 hidnplayr 889
 
5364 hidnplayr 890
        cmp     [eax + STREAM_SOCKET.rcv + RING_BUFFER.size], 0
891
        jne     .more_data
3704 hidnplayr 892
        xor     ebx, ebx                                        ; errorcode = 0 (no error)
3545 hidnplayr 893
        ret
894
 
5364 hidnplayr 895
  .more_data:
896
        call    SOCKET_notify                                   ; Queue another network event
897
        xor     ebx, ebx                                        ; errorcode = 0 (no error)
898
        ret
899
 
3704 hidnplayr 900
  .wouldblock:
901
        push    EWOULDBLOCK
902
        pop     ebx
4219 hidnplayr 903
        xor     ecx, ecx
3704 hidnplayr 904
        ret
905
 
3545 hidnplayr 906
  .peek:
4219 hidnplayr 907
        mov     ecx, [eax + STREAM_SOCKET.rcv + RING_BUFFER.size]
3704 hidnplayr 908
        xor     ebx, ebx
3545 hidnplayr 909
        ret
910
 
911
 
912
;-----------------------------------------------------------------
913
;
914
; SOCKET_send
915
;
916
;
917
;  IN:  socket number in ecx
918
;       pointer to data in edx
919
;       datalength in esi
920
;       flags in edi
921
;  OUT: -1 on error
922
;
923
;-----------------------------------------------------------------
924
align 4
925
SOCKET_send:
926
 
3556 hidnplayr 927
        DEBUGF  DEBUG_NETWORK_VERBOSE, "SOCKET_send: socknum=%u data ptr=%x length=%u flags=%x\n", ecx, edx, esi, edi
3545 hidnplayr 928
 
929
        call    SOCKET_num_to_ptr
3658 hidnplayr 930
        jz      .invalid
3545 hidnplayr 931
 
932
        mov     ecx, esi
933
        mov     esi, edx
934
 
935
        jmp     [eax + SOCKET.snd_proc]
936
 
3658 hidnplayr 937
  .invalid:
3673 hidnplayr 938
        mov     dword[esp+20], EINVAL
3658 hidnplayr 939
        mov     dword[esp+32], -1
940
        ret
3545 hidnplayr 941
 
3658 hidnplayr 942
 
3545 hidnplayr 943
align 4
944
SOCKET_send_udp:
945
 
3556 hidnplayr 946
        DEBUGF  DEBUG_NETWORK_VERBOSE, "SOCKET_send: UDP\n"
3545 hidnplayr 947
 
948
        mov     [esp+32], ecx
949
        call    UDP_output
950
        cmp     eax, -1
3658 hidnplayr 951
        je      .error
3545 hidnplayr 952
        ret
953
 
3658 hidnplayr 954
  .error:
955
        mov     dword[esp+32], -1
3673 hidnplayr 956
        mov     dword[esp+20], EMSGSIZE ; FIXME: UDP_output should return error codes!
3658 hidnplayr 957
        ret
3545 hidnplayr 958
 
3658 hidnplayr 959
 
3545 hidnplayr 960
align 4
961
SOCKET_send_tcp:
962
 
3556 hidnplayr 963
        DEBUGF  DEBUG_NETWORK_VERBOSE, "SOCKET_send: TCP\n"
3545 hidnplayr 964
 
965
        push    eax
966
        add     eax, STREAM_SOCKET.snd
967
        call    SOCKET_ring_write
968
        pop     eax
969
 
970
        mov     [esp+32], ecx
3658 hidnplayr 971
        mov     [eax + SOCKET.errorcode], 0
972
        push    eax
973
        call    TCP_output              ; FIXME: this doesnt look pretty, does it?
974
        pop     eax
975
        mov     eax, [eax + SOCKET.errorcode]
3673 hidnplayr 976
        mov     [esp+20], eax
3545 hidnplayr 977
        ret
978
 
979
 
980
align 4
981
SOCKET_send_ip:
982
 
3556 hidnplayr 983
        DEBUGF  DEBUG_NETWORK_VERBOSE, "SOCKET_send: IPv4\n"
3545 hidnplayr 984
 
985
        mov     [esp+32], ecx
5842 hidnplayr 986
        call    IPv4_output_raw
3545 hidnplayr 987
        cmp     eax, -1
3658 hidnplayr 988
        je      .error
3545 hidnplayr 989
        ret
990
 
3658 hidnplayr 991
  .error:
5842 hidnplayr 992
        mov     dword[esp+32], eax
993
        mov     dword[esp+20], ebx
3658 hidnplayr 994
        ret
3545 hidnplayr 995
 
3658 hidnplayr 996
 
3545 hidnplayr 997
align 4
998
SOCKET_send_icmp:
999
 
3556 hidnplayr 1000
        DEBUGF  DEBUG_NETWORK_VERBOSE, "SOCKET_send: ICMP\n"
3545 hidnplayr 1001
 
1002
        mov     [esp+32], ecx
5842 hidnplayr 1003
        call    ICMP_output_raw
3545 hidnplayr 1004
        cmp     eax, -1
3658 hidnplayr 1005
        je      .error
3545 hidnplayr 1006
        ret
1007
 
3658 hidnplayr 1008
  .error:
5842 hidnplayr 1009
        mov     dword[esp+32], eax
1010
        mov     dword[esp+20], ebx
3658 hidnplayr 1011
        ret
3545 hidnplayr 1012
 
3658 hidnplayr 1013
 
3545 hidnplayr 1014
align 4
1015
SOCKET_send_pppoe:
1016
 
3556 hidnplayr 1017
        DEBUGF  DEBUG_NETWORK_VERBOSE, "SOCKET_send: PPPoE\n"
3545 hidnplayr 1018
 
1019
        mov     [esp+32], ecx
1020
        mov     ebx, [eax + SOCKET.device]
1021
 
3658 hidnplayr 1022
        call    PPPoE_discovery_output  ; FIXME: errorcodes
3545 hidnplayr 1023
        cmp     eax, -1
3658 hidnplayr 1024
        je      .error
3545 hidnplayr 1025
        ret
1026
 
3658 hidnplayr 1027
  .error:
1028
        mov     dword[esp+32], -1
3673 hidnplayr 1029
        mov     dword[esp+20], EMSGSIZE
3658 hidnplayr 1030
        ret
3545 hidnplayr 1031
 
1032
 
3658 hidnplayr 1033
 
3545 hidnplayr 1034
align 4
1035
SOCKET_send_local:
1036
 
1037
        ; does this socket have a PID yet?
1038
        cmp     [eax + SOCKET.PID], 0
1039
        jne     @f
1040
 
1041
        ; Change PID to that of current process
1042
        mov     ebx, [TASK_BASE]
1043
        mov     ebx, [ebx + TASKDATA.pid]
1044
        mov     [eax + SOCKET.PID], ebx
1045
        mov     [eax + SOCKET.TID], ebx         ; currently TID = PID in kolibrios :(
1046
      @@:
1047
        mov     [eax + SOCKET.snd_proc], SOCKET_send_local_
1048
 
1049
align 4
1050
SOCKET_send_local_:
1051
 
3556 hidnplayr 1052
        DEBUGF  DEBUG_NETWORK_VERBOSE, "SOCKET_send: LOCAL\n"
3545 hidnplayr 1053
 
1054
        ; get the other side's socket and check if it still exists
1055
        mov     eax, [eax + SOCKET.device]
1056
        call    SOCKET_check
3658 hidnplayr 1057
        jz      .invalid
3545 hidnplayr 1058
 
1059
        ; allright, shove in the data!
1060
        push    eax
1061
        add     eax, STREAM_SOCKET.rcv
1062
        call    SOCKET_ring_write
1063
        pop     eax
1064
 
1065
        ; return the number of written bytes (or errorcode) to application
1066
        mov     [esp+32], ecx
1067
 
1068
        ; and notify the other end
1069
        call    SOCKET_notify
1070
 
1071
        ret
1072
 
3658 hidnplayr 1073
  .invalid:
1074
        mov     dword[esp+32], -1
3673 hidnplayr 1075
        mov     dword[esp+20], EINVAL
3658 hidnplayr 1076
        ret
3545 hidnplayr 1077
 
3658 hidnplayr 1078
 
3545 hidnplayr 1079
;-----------------------------------------------------------------
1080
;
1081
; SOCKET_get_options
1082
;
1083
;  IN:  ecx = socket number
1084
;       edx = pointer to the options:
1085
;               dd      level, optname, optval, optlen
1086
;  OUT: -1 on error
1087
;
1088
; At moment, uses only pseudo-optname -2 for get last_ack_number for TCP.
1089
; TODO: find best way to notify that send()'ed data were acknowledged
1090
; Also pseudo-optname -3 is valid and returns socket state, one of TCPS_*.
1091
;
1092
;-----------------------------------------------------------------
1093
align 4
1094
SOCKET_get_opt:
1095
 
3556 hidnplayr 1096
        DEBUGF  DEBUG_NETWORK_VERBOSE, "SOCKET_get_opt\n"
3545 hidnplayr 1097
 
1098
        call    SOCKET_num_to_ptr
3658 hidnplayr 1099
        jz      .invalid
3545 hidnplayr 1100
 
1101
        cmp     dword [edx], IP_PROTO_TCP
3658 hidnplayr 1102
        jne     .invalid
3545 hidnplayr 1103
        cmp     dword [edx+4], -2
1104
        je      @f
1105
        cmp     dword [edx+4], -3
3658 hidnplayr 1106
        jne     .invalid
3545 hidnplayr 1107
@@:
1108
;        mov     eax, [edx+12]
1109
;        test    eax, eax
1110
;        jz      .fail
1111
;        cmp     dword [eax], 4
1112
;        mov     dword [eax], 4
1113
;        jb      .fail
1114
;        stdcall net_socket_num_to_addr, ecx
1115
;        test    eax, eax
1116
;        jz      .fail
1117
;        ; todo: check that eax is really TCP socket
1118
;        mov     ecx, [eax + TCP_SOCKET.last_ack_number]
1119
;        cmp     dword [edx+4], -2
1120
;        jz      @f
1121
;        mov     ecx, [eax + TCP_SOCKET.state]
1122
@@:
1123
        mov     eax, [edx+8]
1124
        test    eax, eax
1125
        jz      @f
1126
        mov     [eax], ecx
1127
@@:
1128
        mov     dword [esp+32], 0
1129
        ret
1130
 
3658 hidnplayr 1131
  .invalid:
1132
        mov     dword[esp+32], -1
3673 hidnplayr 1133
        mov     dword[esp+20], EINVAL
3658 hidnplayr 1134
        ret
3545 hidnplayr 1135
 
1136
 
1137
;-----------------------------------------------------------------
1138
;
1139
; SOCKET_set_options
1140
;
1141
;  IN:  ecx = socket number
5842 hidnplayr 1142
;       edx = pointer to socket_options
3545 hidnplayr 1143
;  OUT: -1 on error
1144
;
1145
;-----------------------------------------------------------------
5842 hidnplayr 1146
 
1147
struct socket_options
1148
        level   dd ?
1149
        optname dd ?
1150
        optlen  dd ?
1151
        optval  dd ?
1152
ends
1153
 
3545 hidnplayr 1154
align 4
1155
SOCKET_set_opt:
1156
 
3556 hidnplayr 1157
        DEBUGF  DEBUG_NETWORK_VERBOSE, "SOCKET_set_opt\n"
3545 hidnplayr 1158
 
1159
        call    SOCKET_num_to_ptr
3658 hidnplayr 1160
        jz      .invalid
3545 hidnplayr 1161
 
5842 hidnplayr 1162
        cmp     [edx + socket_options.level], IP_PROTO_IP
1163
        je      .ip
1164
        cmp     [edx + socket_options.level], SOL_SOCKET
3658 hidnplayr 1165
        jne     .invalid
3545 hidnplayr 1166
 
5842 hidnplayr 1167
  .socket:
1168
        cmp     [edx + socket_options.optname], SO_BINDTODEVICE
1169
        jne     .invalid
3545 hidnplayr 1170
 
1171
  .bind:
5842 hidnplayr 1172
        cmp     [edx + socket_options.optlen], 0
3545 hidnplayr 1173
        je      .unbind
1174
 
5842 hidnplayr 1175
        movzx   edx, byte[edx + socket_options.optval]
3600 hidnplayr 1176
        cmp     edx, NET_DEVICES_MAX
3658 hidnplayr 1177
        ja      .invalid
3545 hidnplayr 1178
 
1179
        mov     edx, [NET_DRV_LIST + 4*edx]
1180
        test    edx, edx
3658 hidnplayr 1181
        jz      .already
3545 hidnplayr 1182
        mov     [eax + SOCKET.device], edx
1183
 
5584 hidnplayr 1184
        DEBUGF  DEBUG_NETWORK_VERBOSE, "SOCKET_set_opt: Bound socket %x to device %x\n", eax, edx
3545 hidnplayr 1185
 
3658 hidnplayr 1186
        mov     dword[esp+32], 0        ; success!
3545 hidnplayr 1187
        ret
1188
 
1189
  .unbind:
1190
        mov     [eax + SOCKET.device], 0
1191
 
3658 hidnplayr 1192
        mov     dword[esp+32], 0        ; success!
3545 hidnplayr 1193
        ret
1194
 
5842 hidnplayr 1195
  .ip:
1196
        cmp     [edx + socket_options.optname], IP_TTL
1197
        jne     .invalid
1198
 
1199
  .ttl:
1200
        mov     bl, byte[edx + socket_options.optval]
1201
        mov     [eax + IP_SOCKET.ttl], bl
1202
 
1203
        mov     dword[esp+32], 0        ; success!
1204
        ret
1205
 
3658 hidnplayr 1206
  .already:
3673 hidnplayr 1207
        mov     dword[esp+20], EALREADY
3658 hidnplayr 1208
        mov     dword[esp+32], -1
1209
        ret
3545 hidnplayr 1210
 
5842 hidnplayr 1211
  .invalid:
1212
        mov     dword[esp+20], EINVAL
1213
        mov     dword[esp+32], -1
1214
        ret
3545 hidnplayr 1215
 
3658 hidnplayr 1216
 
1217
 
5842 hidnplayr 1218
 
3545 hidnplayr 1219
;-----------------------------------------------------------------
1220
;
1221
; SOCKET_pair
1222
;
1223
; Allocates a pair of linked LOCAL domain sockets
1224
;
1225
; IN: /
1226
; OUT: eax is socket1 num, -1 on error
1227
;      ebx is socket2 num
1228
;
1229
;-----------------------------------------------------------------
1230
align 4
1231
SOCKET_pair:
1232
 
3556 hidnplayr 1233
        DEBUGF  DEBUG_NETWORK_VERBOSE, "SOCKET_pair\n"
3545 hidnplayr 1234
 
1235
        call    SOCKET_alloc
4535 hidnplayr 1236
        test    eax, eax
3658 hidnplayr 1237
        jz      .nomem1
3545 hidnplayr 1238
        mov     [esp+32], edi   ; application's eax
1239
 
1240
        mov     [eax + SOCKET.Domain], AF_LOCAL
1241
        mov     [eax + SOCKET.Type], SOCK_STREAM
1242
        mov     [eax + SOCKET.Protocol], 0              ;;; CHECKME
1243
        mov     [eax + SOCKET.snd_proc], SOCKET_send_local
1244
        mov     [eax + SOCKET.rcv_proc], SOCKET_receive_local
1245
        mov     [eax + SOCKET.PID], 0
1246
        mov     ebx, eax
1247
 
1248
        call    SOCKET_alloc
4535 hidnplayr 1249
        test    eax, eax
3658 hidnplayr 1250
        jz      .nomem2
3673 hidnplayr 1251
        mov     [esp+20], edi   ; application's ebx
3545 hidnplayr 1252
 
1253
        mov     [eax + SOCKET.Domain], AF_LOCAL
1254
        mov     [eax + SOCKET.Type], SOCK_STREAM
1255
        mov     [eax + SOCKET.Protocol], 0              ;;; CHECKME
1256
        mov     [eax + SOCKET.snd_proc], SOCKET_send_local
1257
        mov     [eax + SOCKET.rcv_proc], SOCKET_receive_local
1258
        mov     [eax + SOCKET.PID], 0
1259
 
1260
        ; Link the two sockets to eachother
1261
        mov     [eax + SOCKET.device], ebx
1262
        mov     [ebx + SOCKET.device], eax
1263
 
1264
        lea     eax, [eax + STREAM_SOCKET.rcv]
1265
        call    SOCKET_ring_create
5155 hidnplayr 1266
        test    eax, eax
1267
        jz      .nomem1
3545 hidnplayr 1268
 
1269
        lea     eax, [ebx + STREAM_SOCKET.rcv]
1270
        call    SOCKET_ring_create
5155 hidnplayr 1271
        test    eax, eax
1272
        jz      .nomem2
3545 hidnplayr 1273
 
1274
        ret
1275
 
3658 hidnplayr 1276
  .nomem2:
3545 hidnplayr 1277
        mov     eax, ebx
1278
        call    SOCKET_free
3658 hidnplayr 1279
  .nomem1:
1280
        mov     dword[esp+32], -1
1281
        mov     dword[esp+28], ENOMEM
1282
        ret
3545 hidnplayr 1283
 
1284
 
1285
 
1286
;-----------------------------------------------------------------
1287
;
1288
; SOCKET_debug
1289
;
1290
;  Copies socket variables to application buffer
1291
;
1292
;  IN:  ecx = socket number
1293
;       edx = pointer to buffer
1294
;
1295
;  OUT: -1 on error
1296
;-----------------------------------------------------------------
1297
align 4
1298
SOCKET_debug:
1299
 
3556 hidnplayr 1300
        DEBUGF  DEBUG_NETWORK_VERBOSE, "SOCKET_debug\n"
3545 hidnplayr 1301
 
1302
        mov     edi, edx
1303
 
1304
        test    ecx, ecx
1305
        jz      .returnall
1306
 
1307
        call    SOCKET_num_to_ptr
3658 hidnplayr 1308
        jz      .invalid
3545 hidnplayr 1309
 
1310
        mov     esi, eax
1311
        mov     ecx, SOCKETBUFFSIZE/4
3711 clevermous 1312
        rep movsd
3545 hidnplayr 1313
 
3658 hidnplayr 1314
        mov     dword[esp+32], 0
3545 hidnplayr 1315
        ret
1316
 
1317
  .returnall:
1318
        mov     ebx, net_sockets
1319
  .next_socket:
1320
        mov     ebx, [ebx + SOCKET.NextPtr]
1321
        test    ebx, ebx
1322
        jz      .done
1323
        mov     eax, [ebx + SOCKET.Number]
1324
        stosd
1325
        jmp     .next_socket
1326
  .done:
1327
        xor     eax, eax
1328
        stosd
3658 hidnplayr 1329
        mov     dword[esp+32], eax
1330
        ret
3545 hidnplayr 1331
 
3658 hidnplayr 1332
  .invalid:
1333
        mov     dword[esp+32], -1
1334
        mov     dword[esp+28], EINVAL
3545 hidnplayr 1335
        ret
1336
 
1337
 
1338
;-----------------------------------------------------------------
1339
;
1340
; SOCKET_find_port
1341
;
1342
; Fills in the local port number for TCP and UDP sockets
1343
; This procedure always works because the number of sockets is
1344
; limited to a smaller number then the number of possible ports
1345
;
1346
;  IN:  eax = socket pointer
1347
;  OUT: /
1348
;
1349
;-----------------------------------------------------------------
1350
align 4
1351
SOCKET_find_port:
1352
 
3556 hidnplayr 1353
        DEBUGF  DEBUG_NETWORK_VERBOSE, "SOCKET_find_port\n"
3545 hidnplayr 1354
 
1355
        push    ebx esi ecx
1356
 
1357
        cmp     [eax + SOCKET.Protocol], IP_PROTO_UDP
1358
        je      .udp
1359
 
1360
        cmp     [eax + SOCKET.Protocol], IP_PROTO_TCP
1361
        je      .tcp
1362
 
1363
        pop     ecx esi ebx
1364
        ret
1365
 
1366
  .udp:
1367
        mov     bx, [last_UDP_port]
1368
        call    .findit
1369
        mov     [last_UDP_port], bx
1370
 
1371
        pop     ecx esi ebx
1372
        ret
1373
 
1374
  .tcp:
1375
        mov     bx, [last_TCP_port]
1376
        call    .findit
1377
        mov     [last_TCP_port], bx
1378
 
1379
        pop     ecx esi ebx
1380
        ret
1381
 
1382
 
1383
  .restart:
1384
        mov     bx, MIN_EPHEMERAL_PORT_N
1385
  .findit:
1386
        cmp     bx, MAX_EPHEMERAL_PORT_N
1387
        je      .restart
1388
 
1389
        add     bh, 1
1390
        adc     bl, 0
1391
 
1392
        call    SOCKET_check_port
1393
        jz      .findit
1394
        ret
1395
 
1396
 
1397
 
1398
;-----------------------------------------------------------------
1399
;
1400
; SOCKET_check_port (to be used with AF_INET only!)
1401
;
1402
; Checks if a local port number is unused
1403
; If the proposed port number is unused, it is filled in in the socket structure
1404
;
1405
;  IN:  eax = socket ptr (to find out if its a TCP/UDP socket)
1406
;        bx = proposed socket number (network byte order)
1407
;
1408
;  OUT:  ZF = set on error
1409
;
1410
;-----------------------------------------------------------------
1411
align 4
1412
SOCKET_check_port:
1413
 
3556 hidnplayr 1414
        DEBUGF  DEBUG_NETWORK_VERBOSE, "SOCKET_check_port: "
3545 hidnplayr 1415
 
3647 hidnplayr 1416
        pusha
1417
        mov     ecx, socket_mutex
1418
        call    mutex_lock
1419
        popa
1420
 
3545 hidnplayr 1421
        mov     ecx, [eax + SOCKET.Protocol]
1422
        mov     edx, [eax + IP_SOCKET.LocalIP]
1423
        mov     esi, net_sockets
1424
 
1425
  .next_socket:
1426
        mov     esi, [esi + SOCKET.NextPtr]
1427
        or      esi, esi
1428
        jz      .port_ok
1429
 
1430
        cmp     [esi + SOCKET.Protocol], ecx
1431
        jne     .next_socket
1432
 
1433
        cmp     [esi + IP_SOCKET.LocalIP], edx
1434
        jne     .next_socket
1435
 
1436
        cmp     [esi + UDP_SOCKET.LocalPort], bx
1437
        jne     .next_socket
1438
 
3647 hidnplayr 1439
        pusha
1440
        mov     ecx, socket_mutex
1441
        call    mutex_unlock
1442
        popa
1443
 
3556 hidnplayr 1444
        DEBUGF  DEBUG_NETWORK_VERBOSE, "local port %x already in use\n", bx  ; FIXME: find a way to print big endian values with debugf
3545 hidnplayr 1445
        ret
1446
 
1447
  .port_ok:
3647 hidnplayr 1448
        pusha
1449
        mov     ecx, socket_mutex
1450
        call    mutex_unlock
1451
        popa
1452
 
3556 hidnplayr 1453
        DEBUGF  DEBUG_NETWORK_VERBOSE, "local port %x is free\n", bx         ; FIXME: find a way to print big endian values with debugf
3545 hidnplayr 1454
        mov     [eax + UDP_SOCKET.LocalPort], bx
1455
        or      bx, bx                                  ; clear the zero-flag
1456
        ret
1457
 
1458
 
1459
 
1460
;-----------------------------------------------------------------
1461
;
1462
; SOCKET_input
1463
;
1464
; Updates a (stateless) socket with received data
1465
;
1466
; Note: the mutex should already be set !
1467
;
1468
;  IN:  eax = socket ptr
1469
;       ecx = data size
1470
;       esi = ptr to data
1471
;       [esp] = ptr to buf
1472
;
1473
;  OUT: /
1474
;
1475
;-----------------------------------------------------------------
1476
align 4
1477
SOCKET_input:
1478
 
3556 hidnplayr 1479
        DEBUGF  DEBUG_NETWORK_VERBOSE, "SOCKET_input: socket=%x, data=%x size=%u\n", eax, esi, ecx
3545 hidnplayr 1480
 
5522 hidnplayr 1481
        push    ecx
3545 hidnplayr 1482
        push    esi
1483
        mov     esi, esp
1484
 
1485
        add_to_queue (eax + SOCKET_QUEUE_LOCATION), SOCKET_QUEUE_SIZE, sizeof.socket_queue_entry, SOCKET_input.full
1486
 
3556 hidnplayr 1487
        DEBUGF  DEBUG_NETWORK_VERBOSE, "SOCKET_input: success\n"
3545 hidnplayr 1488
        add     esp, sizeof.socket_queue_entry
1489
 
1490
        pusha
1491
        lea     ecx, [eax + SOCKET.mutex]
1492
        call    mutex_unlock
1493
        popa
1494
 
1495
        jmp     SOCKET_notify
1496
 
1497
  .full:
3556 hidnplayr 1498
        DEBUGF  DEBUG_NETWORK_VERBOSE, "SOCKET_input: socket %x is full!\n", eax
3545 hidnplayr 1499
 
1500
        pusha
1501
        lea     ecx, [eax + SOCKET.mutex]
1502
        call    mutex_unlock
1503
        popa
1504
 
5842 hidnplayr 1505
        add     esp, 8
5522 hidnplayr 1506
        call    NET_BUFF_free
3545 hidnplayr 1507
        ret
1508
 
1509
 
1510
;--------------------------
1511
;
5522 hidnplayr 1512
; eax = ptr to ring struct (just a buffer of the right size)
3545 hidnplayr 1513
;
1514
align 4
1515
SOCKET_ring_create:
1516
 
1517
        push    esi
1518
        mov     esi, eax
1519
 
1520
        push    edx
5356 serge 1521
        stdcall create_ring_buffer, SOCKET_MAXDATA, PG_SWR
3545 hidnplayr 1522
        pop     edx
5155 hidnplayr 1523
        test    eax, eax
1524
        jz      .fail
3545 hidnplayr 1525
 
3556 hidnplayr 1526
        DEBUGF  DEBUG_NETWORK_VERBOSE, "SOCKET_ring_created: %x\n", eax
3545 hidnplayr 1527
 
1528
        pusha
1529
        lea     ecx, [esi + RING_BUFFER.mutex]
1530
        call    mutex_init
1531
        popa
1532
 
1533
        mov     [esi + RING_BUFFER.start_ptr], eax
1534
        mov     [esi + RING_BUFFER.write_ptr], eax
1535
        mov     [esi + RING_BUFFER.read_ptr], eax
1536
        mov     [esi + RING_BUFFER.size], 0
1537
        add     eax, SOCKET_MAXDATA
1538
        mov     [esi + RING_BUFFER.end_ptr], eax
1539
        mov     eax, esi
1540
 
5155 hidnplayr 1541
  .fail:
5566 hidnplayr 1542
        pop     esi
3545 hidnplayr 1543
        ret
1544
 
1545
;-----------------------------------------------------------------
1546
;
1547
; SOCKET_ring_write
1548
;
1549
; Adds data to a stream socket, and updates write pointer and size
1550
;
1551
;  IN:  eax = ptr to ring struct
1552
;       ecx = data size
1553
;       esi = ptr to data
1554
;
1555
;  OUT: ecx = number of bytes stored
1556
;
1557
;-----------------------------------------------------------------
1558
align 4
1559
SOCKET_ring_write:
1560
 
3556 hidnplayr 1561
        DEBUGF  DEBUG_NETWORK_VERBOSE, "SOCKET_ring_write: ringbuff=%x ptr=%x size=%u\n", eax, esi, ecx
3545 hidnplayr 1562
 
1563
; lock mutex
1564
        pusha
1565
        lea     ecx, [eax + RING_BUFFER.mutex]
1566
        call    mutex_lock                                      ; TODO: check what registers this function actually destroys
1567
        popa
1568
 
1569
; calculate available size
1570
        mov     edi, SOCKET_MAXDATA
1571
        sub     edi, [eax + RING_BUFFER.size]                   ; available buffer size in edi
1572
        cmp     ecx, edi
1573
        jbe     .copy
1574
        mov     ecx, edi
1575
  .copy:
1576
        mov     edi, [eax + RING_BUFFER.write_ptr]
3556 hidnplayr 1577
        DEBUGF  DEBUG_NETWORK_VERBOSE, "SOCKET_ring_write: %u bytes from %x to %x\n", ecx, esi, edi
3545 hidnplayr 1578
 
1579
; update write ptr
1580
        push    edi
1581
        add     edi, ecx
1582
        cmp     edi, [eax + RING_BUFFER.end_ptr]
1583
        jb      @f
1584
        sub     edi, SOCKET_MAXDATA                             ; WRAP
1585
  @@:
5155 hidnplayr 1586
 
3545 hidnplayr 1587
        mov     [eax + RING_BUFFER.write_ptr], edi
1588
        pop     edi
1589
 
1590
; update size
1591
        add     [eax + RING_BUFFER.size], ecx
1592
 
1593
; copy the data
1594
        push    ecx
1595
        shr     ecx, 1
1596
        jnc     .nb
1597
        movsb
1598
  .nb:
1599
        shr     ecx, 1
1600
        jnc     .nw
1601
        movsw
1602
  .nw:
1603
        test    ecx, ecx
1604
        jz      .nd
3711 clevermous 1605
        rep movsd
3545 hidnplayr 1606
  .nd:
1607
        pop     ecx
1608
 
1609
; unlock mutex
4344 hidnplayr 1610
        pusha
3545 hidnplayr 1611
        lea     ecx, [eax + RING_BUFFER.mutex]
1612
        call    mutex_unlock                                    ; TODO: check what registers this function actually destroys
4344 hidnplayr 1613
        popa
3545 hidnplayr 1614
 
1615
        ret
1616
 
1617
;-----------------------------------------------------------------
1618
;
1619
; SOCKET_ring_read
1620
;
1621
;  IN:  eax = ring struct ptr
1622
;       ecx = bytes to read
1623
;       edx = offset
1624
;       edi = ptr to buffer start
1625
;
1626
;  OUT: eax = unchanged
1627
;       ecx = number of bytes read (0 on error)
1628
;       edx = destroyed
1629
;       esi = destroyed
1630
;       edi = ptr to buffer end
1631
;
1632
;-----------------------------------------------------------------
1633
align 4
1634
SOCKET_ring_read:
1635
 
3556 hidnplayr 1636
        DEBUGF  DEBUG_NETWORK_VERBOSE, "SOCKET_ring_read: ringbuff=%x ptr=%x size=%u offset=%x\n", eax, edi, ecx, edx
3545 hidnplayr 1637
 
1638
        pusha
1639
        lea     ecx, [eax + RING_BUFFER.mutex]
1640
        call    mutex_lock                                      ; TODO: check what registers this function actually destroys
1641
        popa
1642
 
1643
        mov     esi, [eax + RING_BUFFER.read_ptr]
1644
        add     esi, edx                                        ; esi = start_ptr + offset
1645
 
1646
        neg     edx
1647
        add     edx, [eax + RING_BUFFER.size]                   ; edx = snd.size - offset
1648
        jle     .no_data_at_all
1649
 
1650
        pusha
1651
        lea     ecx, [eax + RING_BUFFER.mutex]
1652
        call    mutex_unlock                                    ; TODO: check what registers this function actually destroys
1653
        popa
1654
 
1655
        cmp     ecx, edx
1656
        ja      .less_data
1657
 
1658
  .copy:
3556 hidnplayr 1659
        DEBUGF  DEBUG_NETWORK_VERBOSE, "SOCKET_ring_read: %u bytes from %x to %x\n", ecx, esi, edi
3545 hidnplayr 1660
        push    ecx
1661
        shr     ecx, 1
1662
        jnc     .nb
1663
        movsb
1664
  .nb:
1665
        shr     ecx, 1
1666
        jnc     .nw
1667
        movsw
1668
  .nw:
1669
        test    ecx, ecx
1670
        jz      .nd
3711 clevermous 1671
        rep movsd
3545 hidnplayr 1672
  .nd:
1673
        pop     ecx
1674
        ret
1675
 
1676
  .no_data_at_all:
1677
        pusha
1678
        lea     ecx, [eax + RING_BUFFER.mutex]
1679
        call    mutex_unlock                                    ; TODO: check what registers this function actually destroys
1680
        popa
1681
 
3556 hidnplayr 1682
        DEBUGF  DEBUG_NETWORK_VERBOSE, "SOCKET_ring_read: no data at all!\n"
3545 hidnplayr 1683
        xor     ecx, ecx
1684
        ret
1685
 
1686
  .less_data:
1687
        mov     ecx, edx
1688
        jmp     .copy
1689
 
1690
 
1691
;-----------------------------------------------------------------
1692
;
1693
; SOCKET_ring_free
1694
;
1695
; Free's some bytes from the ringbuffer
1696
;
1697
;  IN:  eax = ptr to ring struct
1698
;       ecx = data size
1699
;
1700
;  OUT: ecx = number of bytes free-ed
1701
;
1702
;-----------------------------------------------------------------
1703
align 4
1704
SOCKET_ring_free:
1705
 
3556 hidnplayr 1706
        DEBUGF  DEBUG_NETWORK_VERBOSE, "SOCKET_ring_free: %u bytes from ring %x\n", ecx, eax
3545 hidnplayr 1707
 
1708
        push    eax ecx
1709
        lea     ecx, [eax + RING_BUFFER.mutex]
1710
        call    mutex_lock                                      ; TODO: check what registers this function actually destroys
1711
        pop     ecx eax
1712
 
1713
        sub     [eax + RING_BUFFER.size], ecx
1714
        jb      .error
1715
        add     [eax + RING_BUFFER.read_ptr], ecx
1716
 
1717
        mov     edx, [eax + RING_BUFFER.end_ptr]
1718
        cmp     [eax + RING_BUFFER.read_ptr], edx
1719
        jb      @f
1720
        sub     [eax + RING_BUFFER.read_ptr], SOCKET_MAXDATA
1721
       @@:
1722
 
1723
        push    eax ecx
1724
        lea     ecx, [eax + RING_BUFFER.mutex]                  ; TODO: check what registers this function actually destroys
1725
        call    mutex_unlock
1726
        pop     ecx eax
1727
 
1728
        ret
1729
 
1730
  .error:       ; we could free all available bytes, but that would be stupid, i guess..
3556 hidnplayr 1731
        DEBUGF  DEBUG_NETWORK_VERBOSE, "SOCKET_ring_free: buffer=%x error!\n", eax
3545 hidnplayr 1732
        add     [eax + RING_BUFFER.size], ecx
1733
 
1734
        push    eax
1735
        lea     ecx, [eax + RING_BUFFER.mutex]
1736
        call    mutex_unlock                                    ; TODO: check what registers this function actually destroys
1737
        pop     eax
1738
 
1739
        xor     ecx, ecx
1740
        ret
1741
 
1742
 
1743
;-----------------------------------------------------------------
1744
;
1745
; SOCKET_block
1746
;
1747
; Suspends the thread attached to a socket
1748
;
1749
;  IN:  eax = socket ptr
3674 hidnplayr 1750
;  OUT: eax = unchanged
3545 hidnplayr 1751
;
1752
;-----------------------------------------------------------------
1753
align 4
1754
SOCKET_block:
1755
 
3556 hidnplayr 1756
        DEBUGF  DEBUG_NETWORK_VERBOSE, "SOCKET_block: %x\n", eax
3545 hidnplayr 1757
 
4520 hidnplayr 1758
        push    eax
1759
 
3545 hidnplayr 1760
        pushf
1761
        cli
1762
 
1763
        ; Set the 'socket is blocked' flag
1764
        or      [eax + SOCKET.state], SS_BLOCKED
1765
 
1766
        ; Suspend the thread
1767
        push    edx
1768
        mov     edx, [TASK_BASE]
1769
        mov     [edx + TASKDATA.state], 1               ; Suspended
1770
 
1771
        ; Remember the thread ID so we can wake it up again
1772
        mov     edx, [edx + TASKDATA.pid]
3556 hidnplayr 1773
        DEBUGF  DEBUG_NETWORK_VERBOSE, "SOCKET_block: suspending thread: %u\n", edx
3545 hidnplayr 1774
        mov     [eax + SOCKET.TID], edx
1775
        pop     edx
4520 hidnplayr 1776
        popf
3545 hidnplayr 1777
 
1778
        call    change_task
3674 hidnplayr 1779
        pop     eax
3545 hidnplayr 1780
 
4520 hidnplayr 1781
        DEBUGF  DEBUG_NETWORK_VERBOSE, "SOCKET_block: continuing\n"
3545 hidnplayr 1782
 
1783
        ret
1784
 
1785
 
1786
;-----------------------------------------------------------------
1787
;
1788
; SOCKET_notify
1789
;
1790
; notify's the owner of a socket that something happened
1791
;
1792
;  IN:  eax = socket ptr
3674 hidnplayr 1793
;  OUT: eax = unchanged
3545 hidnplayr 1794
;
1795
;-----------------------------------------------------------------
1796
align 4
1797
SOCKET_notify:
1798
 
3556 hidnplayr 1799
        DEBUGF  DEBUG_NETWORK_VERBOSE, "SOCKET_notify: %x\n", eax
3545 hidnplayr 1800
 
1801
        call    SOCKET_check
1802
        jz      .error
1803
 
4527 hidnplayr 1804
; Find the associated thread's TASK_DATA
1805
        push    ebx ecx esi
1806
        mov     ebx, [eax + SOCKET.TID]
1807
        test    ebx, ebx
1808
        jz      .error2
1809
        xor     ecx, ecx
3545 hidnplayr 1810
        inc     ecx
4527 hidnplayr 1811
        mov     esi, TASK_DATA
1812
  .next:
1813
        cmp     [esi + TASKDATA.pid], ebx
1814
        je      .found
1815
        inc     ecx
3545 hidnplayr 1816
        add     esi, 0x20
1817
        cmp     ecx, [TASK_COUNT]
4527 hidnplayr 1818
        jbe     .next
1819
 
1820
  .error2:
3545 hidnplayr 1821
; PID not found, TODO: close socket!
4527 hidnplayr 1822
        DEBUGF  DEBUG_NETWORK_ERROR, "SOCKET_notify: error finding thread 0x%x !\n", ebx
1823
        pop     esi ecx ebx
1824
        ret
3545 hidnplayr 1825
 
4527 hidnplayr 1826
  .error:
4528 hidnplayr 1827
        DEBUGF  DEBUG_NETWORK_ERROR, "SOCKET_notify: invalid socket ptr: 0x%x !\n", eax
4527 hidnplayr 1828
        ret
1829
 
1830
  .found:
1831
        test    [eax + SOCKET.state], SS_BLOCKED
4528 hidnplayr 1832
        jnz     .un_block
4527 hidnplayr 1833
 
1834
; socket and thread exists and socket is of non blocking type.
1835
; We'll try to flag an event to the thread.
3545 hidnplayr 1836
        shl     ecx, 8
1837
        or      [ecx + SLOT_BASE + APPDATA.event_mask], EVENT_NETWORK
1838
 
3817 hidnplayr 1839
        DEBUGF  DEBUG_NETWORK_VERBOSE, "SOCKET_notify: poking thread %u!\n", eax
4527 hidnplayr 1840
        pop     esi ecx ebx
1841
        ret
3545 hidnplayr 1842
 
4527 hidnplayr 1843
 
4528 hidnplayr 1844
  .un_block:
4527 hidnplayr 1845
; socket and thread exists and socket is of blocking type
1846
; We'll try to unblock it.
1847
        and     [eax + SOCKET.state], not SS_BLOCKED    ; Clear the 'socket is blocked' flag
1848
        mov     [esi + TASKDATA.state], 0               ; Run the thread
3545 hidnplayr 1849
 
3556 hidnplayr 1850
        DEBUGF  DEBUG_NETWORK_VERBOSE, "SOCKET_notify: Unblocked socket!\n"
4527 hidnplayr 1851
        pop     esi ecx ebx
3545 hidnplayr 1852
        ret
1853
 
1854
 
1855
;--------------------------------------------------------------------
1856
;
1857
; SOCKET_alloc
1858
;
1859
; Allocate memory for socket data and put new socket into the list
1860
; Newly created socket is initialized with calling PID and number and
1861
; put into beginning of list (which is a fastest way).
1862
;
1863
; IN:  /
1864
; OUT: eax = 0 on error, socket ptr otherwise
1865
;      edi = socket number
1866
;
1867
;--------------------------------------------------------------------
1868
align 4
1869
SOCKET_alloc:
1870
 
1871
        push    ebx
1872
 
1873
        stdcall kernel_alloc, SOCKETBUFFSIZE
3556 hidnplayr 1874
        DEBUGF  DEBUG_NETWORK_VERBOSE, "SOCKET_alloc: ptr=%x\n", eax
3545 hidnplayr 1875
        or      eax, eax
1876
        jz      .exit
1877
 
1878
; zero-initialize allocated memory
1879
        push    eax
1880
        mov     edi, eax
1881
        mov     ecx, SOCKETBUFFSIZE / 4
1882
        xor     eax, eax
3711 clevermous 1883
        rep stosd
3545 hidnplayr 1884
        pop     eax
1885
 
1886
; set send-and receive procedures to return -1
3658 hidnplayr 1887
        mov     [eax + SOCKET.snd_proc], .not_yet
1888
        mov     [eax + SOCKET.rcv_proc], .not_yet
3545 hidnplayr 1889
 
3647 hidnplayr 1890
        pusha
1891
        mov     ecx, socket_mutex
1892
        call    mutex_lock
1893
        popa
1894
 
3545 hidnplayr 1895
; find first free socket number and use it
1896
        mov     edi, [last_socket_num]
1897
  .next_socket_number:
1898
        inc     edi
1899
        jz      .next_socket_number     ; avoid socket nr 0
1900
        cmp     edi, -1
1901
        je      .next_socket_number     ; avoid socket nr -1
1902
        mov     ebx, net_sockets
1903
  .next_socket:
1904
        mov     ebx, [ebx + SOCKET.NextPtr]
1905
        test    ebx, ebx
1906
        jz      .last_socket
1907
 
1908
        cmp     [ebx + SOCKET.Number], edi
1909
        jne     .next_socket
1910
        jmp     .next_socket_number
1911
 
1912
  .last_socket:
1913
        mov     [last_socket_num], edi
1914
        mov     [eax + SOCKET.Number], edi
3556 hidnplayr 1915
        DEBUGF  DEBUG_NETWORK_VERBOSE, "SOCKET_alloc: number=%u\n", edi
3545 hidnplayr 1916
 
1917
; Fill in PID
1918
        mov     ebx, [TASK_BASE]
1919
        mov     ebx, [ebx + TASKDATA.pid]
1920
        mov     [eax + SOCKET.PID], ebx
1921
        mov     [eax + SOCKET.TID], ebx         ; currently TID = PID in kolibrios :(
1922
 
1923
; init mutex
1924
        pusha
1925
        lea     ecx, [eax + SOCKET.mutex]
1926
        call    mutex_init
1927
        popa
1928
 
1929
; add socket to the list by re-arranging some pointers
1930
        mov     ebx, [net_sockets + SOCKET.NextPtr]
1931
 
1932
        mov     [eax + SOCKET.PrevPtr], net_sockets
1933
        mov     [eax + SOCKET.NextPtr], ebx
1934
 
1935
        test    ebx, ebx
1936
        jz      @f
1937
 
1938
        pusha
1939
        lea     ecx, [ebx + SOCKET.mutex]
1940
        call    mutex_lock
1941
        popa
1942
 
1943
        mov     [ebx + SOCKET.PrevPtr], eax
1944
 
1945
        pusha
1946
        lea     ecx, [ebx + SOCKET.mutex]
1947
        call    mutex_unlock
1948
        popa
1949
       @@:
1950
 
1951
        mov     [net_sockets + SOCKET.NextPtr], eax
3647 hidnplayr 1952
 
1953
        pusha
1954
        mov     ecx, socket_mutex
1955
        call    mutex_unlock
1956
        popa
1957
 
3545 hidnplayr 1958
  .exit:
1959
        pop     ebx
1960
 
1961
        ret
1962
 
3658 hidnplayr 1963
  .not_yet:
3673 hidnplayr 1964
        mov     dword[esp+20], ENOTCONN
3658 hidnplayr 1965
        mov     dword[esp+32], -1
1966
        ret
3545 hidnplayr 1967
 
3658 hidnplayr 1968
 
3545 hidnplayr 1969
;----------------------------------------------------
1970
;
1971
; SOCKET_free
1972
;
1973
; Free socket data memory and remove socket from the list
3884 hidnplayr 1974
; Caller should lock and unlock socket_mutex
3545 hidnplayr 1975
;
1976
; IN:  eax = socket ptr
1977
; OUT: /
1978
;
1979
;----------------------------------------------------
1980
align 4
1981
SOCKET_free:
1982
 
3556 hidnplayr 1983
        DEBUGF  DEBUG_NETWORK_VERBOSE, "SOCKET_free: %x\n", eax
3545 hidnplayr 1984
 
1985
        call    SOCKET_check
1986
        jz      .error
1987
 
1988
        push    ebx
1989
 
1990
        pusha
1991
        lea     ecx, [eax + SOCKET.mutex]
1992
        call    mutex_lock
1993
        popa
1994
 
1995
        cmp     [eax + SOCKET.Domain], AF_INET4
1996
        jnz     .no_tcp
1997
 
1998
        cmp     [eax + SOCKET.Protocol], IP_PROTO_TCP
1999
        jnz     .no_tcp
2000
 
2001
        mov     ebx, eax
2002
        stdcall kernel_free, [ebx + STREAM_SOCKET.rcv.start_ptr]
2003
        stdcall kernel_free, [ebx + STREAM_SOCKET.snd.start_ptr]
2004
        mov     eax, ebx
2005
  .no_tcp:
2006
 
3652 hidnplayr 2007
        DEBUGF  DEBUG_NETWORK_VERBOSE, "SOCKET_free: freeing socket %x\n", eax
3545 hidnplayr 2008
        push    eax                             ; this will be passed to kernel_free
2009
        mov     ebx, [eax + SOCKET.NextPtr]
2010
        mov     eax, [eax + SOCKET.PrevPtr]
2011
 
3556 hidnplayr 2012
        DEBUGF  DEBUG_NETWORK_VERBOSE, "SOCKET_free: linking socket %x to socket %x\n", eax, ebx
3545 hidnplayr 2013
 
2014
        test    eax, eax
2015
        jz      @f
2016
        mov     [eax + SOCKET.NextPtr], ebx
2017
       @@:
2018
 
2019
        test    ebx, ebx
2020
        jz      @f
2021
        mov     [ebx + SOCKET.PrevPtr], eax
2022
       @@:
2023
 
2024
        call    kernel_free
2025
        pop     ebx
2026
 
3652 hidnplayr 2027
        DEBUGF  DEBUG_NETWORK_VERBOSE, "SOCKET_free: success!\n"
2028
 
2029
  .error:
3545 hidnplayr 2030
        ret
2031
 
2032
;------------------------------------
2033
;
2034
; SOCKET_fork
2035
;
2036
; Create a child socket
2037
;
2038
; IN:  socket nr in ebx
2039
; OUT: child socket nr in eax
2040
;
2041
;-----------------------------------
2042
align 4
2043
SOCKET_fork:
2044
 
3556 hidnplayr 2045
        DEBUGF  DEBUG_NETWORK_VERBOSE, "SOCKET_fork: %x\n", ebx
3545 hidnplayr 2046
 
2047
; Exit if backlog queue is full
2048
        mov     eax, [ebx + SOCKET_QUEUE_LOCATION + queue.size]
2049
        cmp     ax, [ebx + SOCKET.backlog]
2050
        jae     .fail
2051
 
2052
; Allocate new socket
2053
        push    ebx
2054
        call    SOCKET_alloc
2055
        pop     ebx
4535 hidnplayr 2056
        test    eax, eax
3545 hidnplayr 2057
        jz      .fail
2058
 
2059
        push    eax
2060
        mov     esi, esp
2061
        add_to_queue (ebx + SOCKET_QUEUE_LOCATION), MAX_backlog, 4, .fail2
2062
        pop     eax
2063
 
2064
; Copy structure from current socket to new
3817 hidnplayr 2065
; We start at PID to preserve the socket num, 2 pointers and mutex
2066
; TID will be filled in later
3545 hidnplayr 2067
        lea     esi, [ebx + SOCKET.PID]
2068
        lea     edi, [eax + SOCKET.PID]
2069
        mov     ecx, (SOCKET_QUEUE_LOCATION - SOCKET.PID + 3)/4
3711 clevermous 2070
        rep movsd
3545 hidnplayr 2071
 
2072
        and     [eax + SOCKET.options], not SO_ACCEPTCON
2073
 
3817 hidnplayr 2074
; Notify owner of parent socket
2075
        push    eax
2076
        mov     eax, ebx
2077
        call    SOCKET_notify
2078
        pop     eax
2079
 
3545 hidnplayr 2080
        ret
2081
 
2082
  .fail2:
2083
        add     esp, 4+4+4
2084
  .fail:
3556 hidnplayr 2085
        DEBUGF  DEBUG_NETWORK_ERROR, "SOCKET_fork: failed\n"
3545 hidnplayr 2086
        xor     eax, eax
2087
        ret
2088
 
2089
 
2090
;---------------------------------------------------
2091
;
2092
; SOCKET_num_to_ptr
2093
;
2094
; Get socket structure address by its number
2095
;
2096
; IN:  ecx = socket number
2097
; OUT: eax = 0 on error, socket ptr otherwise
2098
;       ZF = set on error
2099
;
2100
;---------------------------------------------------
2101
align 4
2102
SOCKET_num_to_ptr:
2103
 
3556 hidnplayr 2104
        DEBUGF  DEBUG_NETWORK_VERBOSE, "SOCKET_num_to_ptr: num=%u ", ecx
3545 hidnplayr 2105
 
3647 hidnplayr 2106
        pusha
2107
        mov     ecx, socket_mutex
2108
        call    mutex_lock
2109
        popa
2110
 
3545 hidnplayr 2111
        mov     eax, net_sockets
2112
 
2113
  .next_socket:
2114
        mov     eax, [eax + SOCKET.NextPtr]
2115
        or      eax, eax
2116
        jz      .error
2117
        cmp     [eax + SOCKET.Number], ecx
2118
        jne     .next_socket
2119
 
2120
        test    eax, eax
2121
 
3647 hidnplayr 2122
        pusha
2123
        mov     ecx, socket_mutex
2124
        call    mutex_unlock
2125
        popa
2126
 
3556 hidnplayr 2127
        DEBUGF  DEBUG_NETWORK_VERBOSE, "ptr=%x\n", eax
3545 hidnplayr 2128
        ret
2129
 
2130
  .error:
3647 hidnplayr 2131
        pusha
2132
        mov     ecx, socket_mutex
2133
        call    mutex_unlock
2134
        popa
2135
 
4574 hidnplayr 2136
        DEBUGF  DEBUG_NETWORK_ERROR, "SOCKET_num_to_ptr: socket %u not found!\n", eax
2137
        DEBUGF  DEBUG_NETWORK_ERROR, "SOCKET_num_to_ptr: caller = 0x%x\n", [esp]
3545 hidnplayr 2138
        ret
2139
 
2140
 
2141
;---------------------------------------------------
2142
;
2143
; SOCKET_ptr_to_num
2144
;
2145
; Get socket number by its address
2146
;
2147
; IN:  eax = socket ptr
2148
; OUT: eax = 0 on error, socket num otherwise
2149
;       ZF = set on error
2150
;
2151
;---------------------------------------------------
2152
align 4
2153
SOCKET_ptr_to_num:
2154
 
3556 hidnplayr 2155
        DEBUGF  DEBUG_NETWORK_VERBOSE, "SOCKET_ptr_to_num: ptr=%x ", eax
3545 hidnplayr 2156
 
2157
        call    SOCKET_check
2158
        jz      .error
2159
 
2160
        mov     eax, [eax + SOCKET.Number]
2161
 
3556 hidnplayr 2162
        DEBUGF  DEBUG_NETWORK_VERBOSE, "num=%u\n", eax
3545 hidnplayr 2163
        ret
2164
 
2165
  .error:
3556 hidnplayr 2166
        DEBUGF  DEBUG_NETWORK_ERROR, "SOCKET_ptr_to_num: not found\n", eax
3545 hidnplayr 2167
        ret
2168
 
2169
 
2170
;---------------------------------------------------
2171
;
2172
; SOCKET_check
2173
;
2174
; checks if the given value is really a socket ptr
2175
;
2176
; IN:  eax = socket ptr
2177
; OUT: eax = 0 on error, unchanged otherwise
2178
;       ZF = set on error
2179
;
2180
;---------------------------------------------------
2181
align 4
2182
SOCKET_check:
2183
 
3556 hidnplayr 2184
        DEBUGF  DEBUG_NETWORK_VERBOSE, "SOCKET_check: %x\n", eax
3545 hidnplayr 2185
 
2186
        push    ebx
2187
        mov     ebx, net_sockets
2188
 
2189
  .next_socket:
2190
        mov     ebx, [ebx + SOCKET.NextPtr]
2191
        or      ebx, ebx
2192
        jz      .done
2193
        cmp     ebx, eax
2194
        jnz     .next_socket
2195
 
2196
  .done:
2197
        mov     eax, ebx
2198
        test    eax, eax
2199
        pop     ebx
2200
 
2201
        ret
2202
 
2203
 
2204
 
2205
;---------------------------------------------------
2206
;
2207
; SOCKET_check_owner
2208
;
2209
; checks if the caller application owns the socket
2210
;
2211
; IN:  eax = socket ptr
2212
; OUT:  ZF = true/false
2213
;
2214
;---------------------------------------------------
2215
align 4
2216
SOCKET_check_owner:
2217
 
3556 hidnplayr 2218
        DEBUGF  DEBUG_NETWORK_VERBOSE, "SOCKET_check_owner: %x\n", eax
3545 hidnplayr 2219
 
2220
        push    ebx
2221
        mov     ebx, [TASK_BASE]
2222
        mov     ebx, [ebx + TASKDATA.pid]
2223
        cmp     [eax + SOCKET.PID], ebx
3711 clevermous 2224
        pop     ebx
3545 hidnplayr 2225
 
2226
        ret
2227
 
2228
 
2229
 
2230
 
2231
;------------------------------------------------------
2232
;
2233
; SOCKET_process_end
2234
;
2235
; Kernel calls this function when a certain process ends
2236
; This function will check if the process had any open sockets
4366 hidnplayr 2237
; And update them accordingly (clean up)
3545 hidnplayr 2238
;
2239
; IN:  edx = pid
2240
; OUT: /
2241
;
2242
;------------------------------------------------------
2243
align 4
2244
SOCKET_process_end:
2245
 
4436 hidnplayr 2246
        ret     ; FIXME
2247
 
4056 hidnplayr 2248
        cmp     [net_sockets + SOCKET.NextPtr], 0       ; Are there any active sockets at all?
2249
        je      .quickret                               ; nope, exit immediately
2250
 
2251
; TODO: run the following code in another thread, to avoid deadlock
2252
 
3556 hidnplayr 2253
        DEBUGF  DEBUG_NETWORK_VERBOSE, "SOCKET_process_end: %x\n", edx
3545 hidnplayr 2254
 
3647 hidnplayr 2255
        pusha
2256
        mov     ecx, socket_mutex
2257
        call    mutex_lock
2258
        popa
2259
 
3545 hidnplayr 2260
        push    ebx
2261
        mov     ebx, net_sockets
2262
 
2263
  .next_socket:
2264
        mov     ebx, [ebx + SOCKET.NextPtr]
2265
  .next_socket_test:
2266
        test    ebx, ebx
2267
        jz      .done
2268
 
2269
        cmp     [ebx + SOCKET.PID], edx
2270
        jne     .next_socket
2271
 
3556 hidnplayr 2272
        DEBUGF  DEBUG_NETWORK_VERBOSE, "SOCKET_process_end: killing socket %x\n", ebx
3545 hidnplayr 2273
 
2274
        mov     [ebx + SOCKET.PID], 0
2275
        mov     eax, ebx
2276
        mov     ebx, [ebx + SOCKET.NextPtr]
3648 hidnplayr 2277
 
3545 hidnplayr 2278
        pusha
3652 hidnplayr 2279
        cmp     [eax + SOCKET.Domain], AF_INET4
2280
        jne     .free
2281
 
2282
        cmp     [eax + SOCKET.Protocol], IP_PROTO_TCP
2283
        jne     .free
2284
 
4366 hidnplayr 2285
        call    TCP_disconnect
3652 hidnplayr 2286
        jmp     .closed
2287
 
2288
  .free:
2289
        call    SOCKET_free
2290
 
2291
  .closed:
3545 hidnplayr 2292
        popa
2293
        jmp     .next_socket_test
2294
 
2295
  .done:
2296
        pop     ebx
2297
 
3647 hidnplayr 2298
        pusha
2299
        mov     ecx, socket_mutex
2300
        call    mutex_unlock
2301
        popa
2302
 
4056 hidnplayr 2303
  .quickret:
3545 hidnplayr 2304
        ret
2305
 
2306
 
2307
 
2308
 
2309
;-----------------------------------------------------------------
2310
;
2311
; SOCKET_is_connecting
2312
;
2313
;  IN:  eax = socket ptr
2314
;  OUT: /
2315
;
2316
;-----------------------------------------------------------------
2317
 
2318
align 4
2319
SOCKET_is_connecting:
2320
 
3556 hidnplayr 2321
        DEBUGF  DEBUG_NETWORK_VERBOSE, "SOCKET_is_connecting: %x\n", eax
3545 hidnplayr 2322
 
4025 hidnplayr 2323
        and     [eax + SOCKET.state], not (SS_ISCONNECTED + SS_ISDISCONNECTING + SS_ISCONFIRMING)
2324
        or      [eax + SOCKET.state], SS_ISCONNECTING
3545 hidnplayr 2325
 
4025 hidnplayr 2326
        ret
3545 hidnplayr 2327
 
2328
 
2329
 
2330
;-----------------------------------------------------------------
2331
;
2332
; SOCKET_is_connected
2333
;
2334
;  IN:  eax = socket ptr
2335
;  OUT: /
2336
;
2337
;-----------------------------------------------------------------
2338
 
2339
align 4
2340
SOCKET_is_connected:
2341
 
3556 hidnplayr 2342
        DEBUGF  DEBUG_NETWORK_VERBOSE, "SOCKET_is_connected: %x\n", eax
3545 hidnplayr 2343
 
3674 hidnplayr 2344
        and     [eax + SOCKET.state], not (SS_ISCONNECTING + SS_ISDISCONNECTING + SS_ISCONFIRMING)
2345
        or      [eax + SOCKET.state], SS_ISCONNECTED
3545 hidnplayr 2346
 
2347
        jmp     SOCKET_notify
2348
 
2349
 
2350
 
2351
 
2352
;-----------------------------------------------------------------
2353
;
2354
; SOCKET_is_disconnecting
2355
;
2356
;  IN:  eax = socket ptr
2357
;  OUT: /
2358
;
2359
;-----------------------------------------------------------------
2360
 
2361
align 4
2362
SOCKET_is_disconnecting:
2363
 
3556 hidnplayr 2364
        DEBUGF  DEBUG_NETWORK_VERBOSE, "SOCKET_is_disconnecting: %x\n", eax
3545 hidnplayr 2365
 
3674 hidnplayr 2366
        and     [eax + SOCKET.state], not (SS_ISCONNECTING)
2367
        or      [eax + SOCKET.state], SS_ISDISCONNECTING + SS_CANTRCVMORE + SS_CANTSENDMORE
3545 hidnplayr 2368
 
2369
        jmp     SOCKET_notify
2370
 
2371
 
2372
 
2373
;-----------------------------------------------------------------
2374
;
2375
; SOCKET_is_disconnected
2376
;
2377
;  IN:  eax = socket ptr
2378
;  OUT: /
2379
;
2380
;-----------------------------------------------------------------
2381
 
2382
align 4
2383
SOCKET_is_disconnected:
2384
 
3556 hidnplayr 2385
        DEBUGF  DEBUG_NETWORK_VERBOSE, "SOCKET_is_disconnected: %x\n", eax
3545 hidnplayr 2386
 
3674 hidnplayr 2387
        and     [eax + SOCKET.state], not (SS_ISCONNECTING + SS_ISCONNECTED + SS_ISDISCONNECTING)
2388
        or      [eax + SOCKET.state], SS_CANTRCVMORE + SS_CANTSENDMORE
3545 hidnplayr 2389
 
2390
 
2391
        jmp     SOCKET_notify
2392
 
2393
 
2394
 
2395
;-----------------------------------------------------------------
2396
;
2397
; SOCKET_cant_recv_more
2398
;
2399
;  IN:  eax = socket ptr
2400
;  OUT: /
2401
;
2402
;-----------------------------------------------------------------
2403
 
2404
align 4
2405
SOCKET_cant_recv_more:
2406
 
3556 hidnplayr 2407
        DEBUGF  DEBUG_NETWORK_VERBOSE, "SOCKET_cant_recv_more: %x\n", eax
3545 hidnplayr 2408
 
3674 hidnplayr 2409
        or      [eax + SOCKET.state], SS_CANTRCVMORE
3545 hidnplayr 2410
 
3565 hidnplayr 2411
        call    SOCKET_notify
2412
 
3545 hidnplayr 2413
        ret
2414
 
2415
 
2416
 
2417
;-----------------------------------------------------------------
2418
;
2419
; SOCKET_cant_send_more
2420
;
2421
;  IN:  eax = socket ptr
2422
;  OUT: /
2423
;
2424
;-----------------------------------------------------------------
2425
 
2426
align 4
2427
SOCKET_cant_send_more:
2428
 
3556 hidnplayr 2429
        DEBUGF  DEBUG_NETWORK_VERBOSE, "SOCKET_cant_send_more: %x\n", eax
3545 hidnplayr 2430
 
3674 hidnplayr 2431
        or      [eax + SOCKET.state], SS_CANTSENDMORE
3658 hidnplayr 2432
        mov     [eax + SOCKET.snd_proc], .notconn
3545 hidnplayr 2433
 
3565 hidnplayr 2434
        call    SOCKET_notify
2435
 
3658 hidnplayr 2436
        ret
2437
 
2438
  .notconn:
3673 hidnplayr 2439
        mov     dword[esp+20], ENOTCONN
3658 hidnplayr 2440
        mov     dword[esp+32], -1
5356 serge 2441
        ret