Subversion Repositories Kolibri OS

Rev

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

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