Subversion Repositories Kolibri OS

Rev

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

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