Subversion Repositories Kolibri OS

Rev

Rev 4056 | Rev 4339 | 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 ?
4030 hidnplayr 42
        connect_proc            dd ?
3545 hidnplayr 43
 
44
ends
45
 
46
struct  IP_SOCKET               SOCKET
47
 
48
        LocalIP                 rd 4 ; network byte order
49
        RemoteIP                rd 4 ; network byte order
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 ?
96
        SND_SSTHRESH            dd ?
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
3600 hidnplayr 130
        timer_flags             dd ?
3545 hidnplayr 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
4021 hidnplayr 135
        timer_connect           dd ?
3545 hidnplayr 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
        temp_bits               db ?
145
                                rb 3 ; align
146
 
4021 hidnplayr 147
 
3545 hidnplayr 148
ends
149
 
150
struct  UDP_SOCKET              IP_SOCKET
151
 
152
        LocalPort               dw ? ; network byte order
153
        RemotePort              dw ? ; network byte order
154
 
155
ends
156
 
157
 
158
struct  ICMP_SOCKET             IP_SOCKET
159
 
160
        Identifier              dw ?
161
 
162
ends
163
 
164
 
165
struct  RING_BUFFER
166
 
167
        mutex                   MUTEX
168
        start_ptr               dd ? ; Pointer to start of buffer
169
        end_ptr                 dd ? ; pointer to end of buffer
170
        read_ptr                dd ? ; Read pointer
171
        write_ptr               dd ? ; Write pointer
172
        size                    dd ? ; Number of bytes buffered
173
 
174
ends
175
 
176
struct  STREAM_SOCKET           TCP_SOCKET
177
 
178
        rcv                     RING_BUFFER
179
        snd                     RING_BUFFER
180
 
181
ends
182
 
183
struct  socket_queue_entry
184
 
185
        data_ptr                dd ?
186
        buf_ptr                 dd ?
187
        data_size               dd ?
188
 
189
ends
190
 
191
 
192
SOCKETBUFFSIZE          = 4096     ; in bytes
193
 
194
SOCKET_QUEUE_SIZE       = 10       ; maximum number of incoming packets queued for 1 socket
195
; the incoming packet queue for sockets is placed in the socket struct itself, at this location from start
196
SOCKET_QUEUE_LOCATION   = (SOCKETBUFFSIZE - SOCKET_QUEUE_SIZE*sizeof.socket_queue_entry - sizeof.queue)
197
 
198
uglobal
3698 hidnplayr 199
align 4
200
 
3545 hidnplayr 201
        net_sockets     rd 4
202
        last_socket_num dd ?
203
        last_UDP_port   dw ? ; These values give the number of the last used ephemeral port
204
        last_TCP_port   dw ? ;
3647 hidnplayr 205
        socket_mutex    MUTEX
3698 hidnplayr 206
 
3545 hidnplayr 207
endg
208
 
209
 
210
;-----------------------------------------------------------------
211
;
212
; SOCKET_init
213
;
214
;-----------------------------------------------------------------
215
macro   SOCKET_init {
216
 
217
        xor     eax, eax
218
        mov     edi, net_sockets
219
        mov     ecx, 5
3711 clevermous 220
        rep stosd
3545 hidnplayr 221
 
222
       @@:
223
        pseudo_random eax
3600 hidnplayr 224
        cmp     ax, EPHEMERAL_PORT_MIN
3545 hidnplayr 225
        jb      @r
3600 hidnplayr 226
        cmp     ax, EPHEMERAL_PORT_MAX
3545 hidnplayr 227
        ja      @r
228
        xchg    al, ah
229
        mov     [last_UDP_port], ax
230
 
231
       @@:
232
        pseudo_random eax
3600 hidnplayr 233
        cmp     ax, EPHEMERAL_PORT_MIN
3545 hidnplayr 234
        jb      @r
3600 hidnplayr 235
        cmp     ax, EPHEMERAL_PORT_MAX
3545 hidnplayr 236
        ja      @r
237
        xchg    al, ah
238
        mov     [last_TCP_port], ax
239
 
3647 hidnplayr 240
        mov     ecx, socket_mutex
241
        call    mutex_init
242
 
3545 hidnplayr 243
}
244
 
245
;-----------------------------------------------------------------
246
;
247
; Socket API (function 74)
248
;
249
;-----------------------------------------------------------------
250
align 4
251
sys_socket:
252
 
3673 hidnplayr 253
        mov     dword[esp+20], 0        ; Set error code to 0
3659 hidnplayr 254
 
3545 hidnplayr 255
        cmp     ebx, 255
256
        jz      SOCKET_debug
257
 
258
        cmp     ebx, .number
3658 hidnplayr 259
        ja      .error
3545 hidnplayr 260
        jmp     dword [.table + 4*ebx]
261
 
262
  .table:
263
        dd      SOCKET_open     ; 0
264
        dd      SOCKET_close    ; 1
265
        dd      SOCKET_bind     ; 2
266
        dd      SOCKET_listen   ; 3
267
        dd      SOCKET_connect  ; 4
268
        dd      SOCKET_accept   ; 5
269
        dd      SOCKET_send     ; 6
270
        dd      SOCKET_receive  ; 7
271
        dd      SOCKET_set_opt  ; 8
272
        dd      SOCKET_get_opt  ; 9
273
        dd      SOCKET_pair     ; 10
274
  .number = ($ - .table) / 4 - 1
275
 
3658 hidnplayr 276
  .error:
277
        mov     dword[esp+32], -1
3673 hidnplayr 278
        mov     dword[esp+20], EINVAL
3545 hidnplayr 279
 
280
        ret
281
 
282
;-----------------------------------------------------------------
283
;
284
; SOCKET_open
285
;
286
;  IN:  domain in ecx
287
;       type in edx
288
;       protocol in esi
289
;  OUT: eax is socket num, -1 on error
290
;
291
;-----------------------------------------------------------------
292
align 4
293
SOCKET_open:
294
 
3556 hidnplayr 295
        DEBUGF  DEBUG_NETWORK_VERBOSE, "SOCKET_open: domain=%u type=%u protocol=%x ", ecx, edx, esi
3545 hidnplayr 296
 
297
        push    ecx edx esi
298
        call    SOCKET_alloc
299
        pop     esi edx ecx
3658 hidnplayr 300
        jz      .nobuffs
3545 hidnplayr 301
 
302
        mov     [esp+32], edi                   ; return socketnumber
3556 hidnplayr 303
        DEBUGF  DEBUG_NETWORK_VERBOSE, "socknum=%u\n", edi
3545 hidnplayr 304
 
3705 hidnplayr 305
        test    edx, SO_NONBLOCK
306
        jz      @f
307
        or      [eax + SOCKET.options], SO_NONBLOCK
308
        and     edx, not SO_NONBLOCK
309
  @@:
3545 hidnplayr 310
 
311
        mov     [eax + SOCKET.Domain], ecx
312
        mov     [eax + SOCKET.Type], edx
313
        mov     [eax + SOCKET.Protocol], esi
4030 hidnplayr 314
        mov     [eax + SOCKET.connect_proc], connect_notsupp
3545 hidnplayr 315
 
316
        cmp     ecx, AF_INET4
317
        jne     .no_inet4
318
 
319
        cmp     edx, SOCK_DGRAM
320
        je      .udp
321
 
322
        cmp     edx, SOCK_STREAM
323
        je      .tcp
324
 
325
        cmp     edx, SOCK_RAW
326
        je      .raw
327
 
328
  .no_inet4:
329
        cmp     ecx, AF_PPP
330
        jne     .no_ppp
331
 
332
        cmp     esi, PPP_PROTO_ETHERNET
333
        je      .pppoe
334
 
335
  .no_ppp:
3658 hidnplayr 336
  .unsupported:
337
        push    eax
338
        call    SOCKET_free
339
        pop     eax
3673 hidnplayr 340
        mov     dword[esp+20], EOPNOTSUPP
3658 hidnplayr 341
        mov     dword[esp+32], -1
3545 hidnplayr 342
        ret
343
 
3658 hidnplayr 344
  .nobuffs:
3673 hidnplayr 345
        mov     dword[esp+20], ENOBUFS
3658 hidnplayr 346
        mov     dword[esp+32], -1
347
        ret
348
 
3545 hidnplayr 349
  .raw:
350
        test    esi, esi       ; IP_PROTO_IP
3658 hidnplayr 351
        jz      .raw_ip
3545 hidnplayr 352
 
353
        cmp     esi, IP_PROTO_ICMP
3658 hidnplayr 354
        je      .raw_icmp
3545 hidnplayr 355
 
3658 hidnplayr 356
        jmp     .unsupported
3545 hidnplayr 357
 
358
align 4
359
  .udp:
360
        mov     [eax + SOCKET.Protocol], IP_PROTO_UDP
361
        mov     [eax + SOCKET.snd_proc], SOCKET_send_udp
362
        mov     [eax + SOCKET.rcv_proc], SOCKET_receive_dgram
4030 hidnplayr 363
        mov     [eax + SOCKET.connect_proc], UDP_connect
3545 hidnplayr 364
        ret
365
 
366
align 4
367
  .tcp:
368
        mov     [eax + SOCKET.Protocol], IP_PROTO_TCP
369
        mov     [eax + SOCKET.snd_proc], SOCKET_send_tcp
370
        mov     [eax + SOCKET.rcv_proc], SOCKET_receive_stream
4030 hidnplayr 371
        mov     [eax + SOCKET.connect_proc], TCP_connect
3545 hidnplayr 372
 
373
        TCP_init_socket eax
374
        ret
375
 
376
 
377
align 4
3658 hidnplayr 378
  .raw_ip:
3545 hidnplayr 379
        mov     [eax + SOCKET.snd_proc], SOCKET_send_ip
380
        mov     [eax + SOCKET.rcv_proc], SOCKET_receive_dgram
4030 hidnplayr 381
        mov     [eax + SOCKET.connect_proc], IPv4_connect
3545 hidnplayr 382
        ret
383
 
384
 
385
align 4
3658 hidnplayr 386
  .raw_icmp:
3545 hidnplayr 387
        mov     [eax + SOCKET.snd_proc], SOCKET_send_icmp
388
        mov     [eax + SOCKET.rcv_proc], SOCKET_receive_dgram
4030 hidnplayr 389
        mov     [eax + SOCKET.connect_proc], IPv4_connect
3545 hidnplayr 390
        ret
391
 
392
align 4
393
  .pppoe:
394
        push    eax
395
        init_queue (eax + SOCKET_QUEUE_LOCATION)        ; Set up data receiving queue
396
        pop     eax
397
 
398
        mov     [eax + SOCKET.snd_proc], SOCKET_send_pppoe
399
        mov     [eax + SOCKET.rcv_proc], SOCKET_receive_dgram
400
        ret
401
 
402
 
403
;-----------------------------------------------------------------
404
;
405
; SOCKET_bind
406
;
407
;  IN:  socket number in ecx
408
;       pointer to sockaddr struct in edx
409
;       length of that struct in esi
410
;  OUT: 0 on success
411
;
412
;-----------------------------------------------------------------
413
align 4
414
SOCKET_bind:
415
 
3556 hidnplayr 416
        DEBUGF  DEBUG_NETWORK_VERBOSE, "SOCKET_bind: socknum=%u sockaddr=%x length=%u\n", ecx, edx, esi
3545 hidnplayr 417
 
418
        call    SOCKET_num_to_ptr
3658 hidnplayr 419
        jz      .invalid
3545 hidnplayr 420
 
421
        cmp     esi, 2
3658 hidnplayr 422
        jb      .invalid
3545 hidnplayr 423
 
4052 hidnplayr 424
        cmp     [eax + UDP_SOCKET.LocalPort], 0         ; Socket can only be bound once
425
        jnz     .invalid
426
 
3545 hidnplayr 427
        cmp     word [edx], AF_INET4
428
        je      .af_inet4
429
 
430
        cmp     word [edx], AF_LOCAL
431
        je      .af_local
432
 
3658 hidnplayr 433
  .notsupp:
3673 hidnplayr 434
        mov     dword[esp+20], EOPNOTSUPP
3658 hidnplayr 435
        mov     dword[esp+32], -1
436
        ret
3545 hidnplayr 437
 
3658 hidnplayr 438
  .invalid:
3673 hidnplayr 439
        mov     dword[esp+20], EINVAL
3658 hidnplayr 440
        mov     dword[esp+32], -1
441
        ret
442
 
3545 hidnplayr 443
  .af_local:
444
        ; TODO: write code here
3658 hidnplayr 445
        mov     dword[esp+32], 0
3545 hidnplayr 446
        ret
447
 
448
  .af_inet4:
449
        cmp     esi, 6
3658 hidnplayr 450
        jb      .invalid
3545 hidnplayr 451
 
452
        cmp     [eax + SOCKET.Protocol], IP_PROTO_UDP
453
        je      .udp
454
 
455
        cmp     [eax + SOCKET.Protocol], IP_PROTO_TCP
456
        je      .tcp
457
 
3658 hidnplayr 458
        jmp     .notsupp
3545 hidnplayr 459
 
460
  .tcp:
461
  .udp:
462
 
4052 hidnplayr 463
        pushd   [edx + 4]                       ; First, fill in the IP
464
        popd    [eax + IP_SOCKET.LocalIP]
3545 hidnplayr 465
 
4052 hidnplayr 466
        mov     bx, [edx + 2]                   ; Did caller specify a local port?
467
        test    bx, bx
468
        jnz     .just_check
469
        call    SOCKET_find_port                ; Nope, find an ephemeral one
470
        jmp     .done
471
 
472
  .just_check:
473
        call    SOCKET_check_port               ; Yes, check if it's still available
474
        jz      .addrinuse                      ; ZF is set by socket_check_port on error
475
 
476
  .done:
3556 hidnplayr 477
        DEBUGF  DEBUG_NETWORK_VERBOSE, "SOCKET_bind: local ip=%u.%u.%u.%u\n",\
3545 hidnplayr 478
        [eax + IP_SOCKET.LocalIP + 0]:1,[eax + IP_SOCKET.LocalIP + 1]:1,\
479
        [eax + IP_SOCKET.LocalIP + 2]:1,[eax + IP_SOCKET.LocalIP + 3]:1
480
 
3658 hidnplayr 481
        mov     dword[esp+32], 0
3545 hidnplayr 482
        ret
483
 
3658 hidnplayr 484
  .addrinuse:
485
        mov     dword[esp+32], -1
3673 hidnplayr 486
        mov     dword[esp+20], EADDRINUSE
3658 hidnplayr 487
        ret
3545 hidnplayr 488
 
489
 
490
 
3658 hidnplayr 491
 
3545 hidnplayr 492
;-----------------------------------------------------------------
493
;
494
; SOCKET_connect
495
;
496
;  IN:  socket number in ecx
497
;       pointer to sockaddr struct in edx
498
;       length of that struct in esi
499
;  OUT: 0 on success
500
;
501
;-----------------------------------------------------------------
502
align 4
503
SOCKET_connect:
504
 
3556 hidnplayr 505
        DEBUGF  DEBUG_NETWORK_VERBOSE, "SOCKET_connect: socknum=%u sockaddr=%x length=%u\n", ecx, edx, esi
3545 hidnplayr 506
 
507
        call    SOCKET_num_to_ptr
3658 hidnplayr 508
        jz      .invalid
3545 hidnplayr 509
 
510
        cmp     esi, 8
3658 hidnplayr 511
        jb      .invalid
3545 hidnplayr 512
 
4025 hidnplayr 513
        cmp     [eax + SOCKET.state], SS_ISCONNECTING
514
        je      .already
515
 
516
        test    [eax + SOCKET.options], SO_ACCEPTCON
517
        jnz     .notsupp
518
 
4030 hidnplayr 519
        call    [eax + SOCKET.connect_proc]
3545 hidnplayr 520
 
4030 hidnplayr 521
        mov     dword[esp+20], ebx
522
        mov     dword[esp+32], eax
523
        ret
524
 
525
 
3658 hidnplayr 526
  .notsupp:
3673 hidnplayr 527
        mov     dword[esp+20], EOPNOTSUPP
3658 hidnplayr 528
        mov     dword[esp+32], -1
529
        ret
3545 hidnplayr 530
 
3658 hidnplayr 531
  .invalid:
3673 hidnplayr 532
        mov     dword[esp+20], EINVAL
3658 hidnplayr 533
        mov     dword[esp+32], -1
534
        ret
535
 
4025 hidnplayr 536
  .already:
537
        mov     dword[esp+20], EALREADY
538
        mov     dword[esp+32], -1
539
        ret
540
 
541
 
4030 hidnplayr 542
connect_notsupp:
543
        xor     eax, eax
544
        dec     eax
545
        mov     ebx, EOPNOTSUPP
3545 hidnplayr 546
        ret
547
 
4025 hidnplayr 548
 
3545 hidnplayr 549
;-----------------------------------------------------------------
550
;
551
; SOCKET_listen
552
;
553
;  IN:  socket number in ecx
554
;       backlog in edx
555
;  OUT: eax is socket num, -1 on error
556
;
557
;-----------------------------------------------------------------
558
align 4
559
SOCKET_listen:
560
 
3556 hidnplayr 561
        DEBUGF  DEBUG_NETWORK_VERBOSE, "SOCKET_listen: socknum=%u backlog=%u\n", ecx, edx
3545 hidnplayr 562
 
563
        call    SOCKET_num_to_ptr
3658 hidnplayr 564
        jz      .invalid
3545 hidnplayr 565
 
566
        cmp     [eax + SOCKET.Domain], AF_INET4
3658 hidnplayr 567
        jne     .notsupp
3545 hidnplayr 568
 
569
        cmp     [eax + SOCKET.Protocol], IP_PROTO_TCP
3658 hidnplayr 570
        jne     .invalid
3545 hidnplayr 571
 
572
        cmp     [eax + TCP_SOCKET.LocalPort], 0
3658 hidnplayr 573
        je      .already
3545 hidnplayr 574
 
575
        cmp     [eax + IP_SOCKET.LocalIP], 0
576
        jne     @f
3601 hidnplayr 577
        push    [IP_LIST + 4]           ;;; fixme!!!!
3545 hidnplayr 578
        pop     [eax + IP_SOCKET.LocalIP]
579
       @@:
580
 
581
        cmp     edx, MAX_backlog
582
        jbe     @f
583
        mov     edx, MAX_backlog
584
       @@:
585
 
586
        mov     [eax + SOCKET.backlog], dx
587
        or      [eax + SOCKET.options], SO_ACCEPTCON
588
        mov     [eax + TCP_SOCKET.t_state], TCPS_LISTEN
589
        mov     [eax + TCP_SOCKET.timer_keepalive], 0           ; disable keepalive timer
590
 
591
        push    eax
592
        init_queue (eax + SOCKET_QUEUE_LOCATION)                ; Set up sockets queue
593
        pop     eax
594
 
3658 hidnplayr 595
        mov     dword[esp+32], 0
596
        ret
3545 hidnplayr 597
 
3658 hidnplayr 598
  .notsupp:
3673 hidnplayr 599
        mov     dword[esp+20], EOPNOTSUPP
3658 hidnplayr 600
        mov     dword[esp+32], -1
3545 hidnplayr 601
        ret
602
 
3658 hidnplayr 603
  .invalid:
3673 hidnplayr 604
        mov     dword[esp+20], EINVAL
3658 hidnplayr 605
        mov     dword[esp+32], -1
606
        ret
3545 hidnplayr 607
 
3658 hidnplayr 608
  .already:
3673 hidnplayr 609
        mov     dword[esp+20], EALREADY
3658 hidnplayr 610
        mov     dword[esp+32], -1
611
        ret
612
 
613
 
3545 hidnplayr 614
;-----------------------------------------------------------------
615
;
616
; SOCKET_accept
617
;
618
;  IN:  socket number in ecx
619
;       addr in edx
620
;       addrlen in esi
621
;  OUT: eax is socket num, -1 on error
622
;
623
;-----------------------------------------------------------------
624
align 4
625
SOCKET_accept:
626
 
3556 hidnplayr 627
        DEBUGF  DEBUG_NETWORK_VERBOSE, "SOCKET_accept: socknum=%u sockaddr=%x length=%u\n", ecx, edx, esi
3545 hidnplayr 628
 
629
        call    SOCKET_num_to_ptr
3658 hidnplayr 630
        jz      .invalid
3545 hidnplayr 631
 
632
        test    [eax + SOCKET.options], SO_ACCEPTCON
3658 hidnplayr 633
        jz      .invalid
3545 hidnplayr 634
 
635
        cmp     [eax + SOCKET.Domain], AF_INET4
3658 hidnplayr 636
        jne     .notsupp
3545 hidnplayr 637
 
638
        cmp     [eax + SOCKET.Protocol], IP_PROTO_TCP
3658 hidnplayr 639
        jne     .invalid
3545 hidnplayr 640
 
641
  .loop:
642
        get_from_queue (eax + SOCKET_QUEUE_LOCATION), MAX_backlog, 4, .block
643
 
644
; Ok, we got a socket ptr
645
        mov     eax, [esi]
646
 
647
; Change thread ID to that of the current thread
648
        mov     ebx, [TASK_BASE]
649
        mov     ebx, [ebx + TASKDATA.pid]
650
        mov     [eax + SOCKET.TID], ebx
651
 
3817 hidnplayr 652
; Convert it to a socket number
653
        call    SOCKET_ptr_to_num
654
        jz      .invalid        ; FIXME ?
655
 
3545 hidnplayr 656
; and return it to caller
657
        mov     [esp+32], eax
658
        ret
659
 
660
  .block:
661
        test    [eax + SOCKET.options], SO_NONBLOCK
3658 hidnplayr 662
        jnz     .wouldblock
3545 hidnplayr 663
 
664
        call    SOCKET_block
665
        jmp     .loop
666
 
3658 hidnplayr 667
  .wouldblock:
3673 hidnplayr 668
        mov     dword[esp+20], EWOULDBLOCK
3658 hidnplayr 669
        mov     dword[esp+32], -1
670
        ret
671
 
672
  .invalid:
3673 hidnplayr 673
        mov     dword[esp+20], EINVAL
3658 hidnplayr 674
        mov     dword[esp+32], -1
675
        ret
676
 
677
  .notsupp:
3673 hidnplayr 678
        mov     dword[esp+20], EOPNOTSUPP
3658 hidnplayr 679
        mov     dword[esp+32], -1
680
        ret
681
 
3545 hidnplayr 682
;-----------------------------------------------------------------
683
;
684
; SOCKET_close
685
;
686
;  IN:  socket number in ecx
687
;  OUT: eax is socket num, -1 on error
688
;
689
;-----------------------------------------------------------------
690
align 4
691
SOCKET_close:
692
 
3556 hidnplayr 693
        DEBUGF  DEBUG_NETWORK_VERBOSE, "SOCKET_close: socknum=%u\n", ecx
3545 hidnplayr 694
 
695
        call    SOCKET_num_to_ptr
3658 hidnplayr 696
        jz      .invalid
3545 hidnplayr 697
 
3658 hidnplayr 698
        mov     dword[esp+32], 0                                ; The socket exists, so we will succeed in closing it.
3545 hidnplayr 699
 
700
        or      [eax + SOCKET.options], SO_NONBLOCK             ; Mark the socket as non blocking, we dont want it to block any longer!
701
 
702
        test    [eax + SOCKET.state], SS_BLOCKED                ; Is the socket still in blocked state?
703
        jz      @f
704
        call    SOCKET_notify.unblock                           ; Unblock it.
705
  @@:
706
 
707
        cmp     [eax + SOCKET.Domain], AF_INET4
708
        jne     .free
709
 
710
        cmp     [eax + SOCKET.Protocol], IP_PROTO_TCP
711
        je      .tcp
712
 
713
  .free:
714
        call    SOCKET_free
715
        ret
716
 
717
  .tcp:
718
        cmp     [eax + TCP_SOCKET.t_state], TCPS_SYN_RECEIVED    ; state must be LISTEN, SYN_SENT or CLOSED
719
        jb      .free
720
 
721
        call    TCP_usrclosed
722
        call    TCP_output      ;;;; Fixme: is this nescessary??
3646 hidnplayr 723
        call    SOCKET_free
3545 hidnplayr 724
 
725
        ret
726
 
727
 
3658 hidnplayr 728
  .invalid:
3673 hidnplayr 729
        mov     dword[esp+20], EINVAL
3658 hidnplayr 730
        mov     dword[esp+32], -1
731
        ret
732
 
733
 
3545 hidnplayr 734
;-----------------------------------------------------------------
735
;
736
; SOCKET_receive
737
;
738
;  IN:  socket number in ecx
739
;       addr to buffer in edx
740
;       length of buffer in esi
741
;       flags in edi
742
;  OUT: eax is number of bytes copied, -1 on error
743
;
744
;-----------------------------------------------------------------
745
align 4
746
SOCKET_receive:
747
 
3556 hidnplayr 748
        DEBUGF  DEBUG_NETWORK_VERBOSE, "SOCKET_receive: socknum=%u bufaddr=%x buflength=%u flags=%x\n", ecx, edx, esi, edi
3545 hidnplayr 749
 
750
        call    SOCKET_num_to_ptr
3658 hidnplayr 751
        jz      .invalid
3545 hidnplayr 752
 
3704 hidnplayr 753
  .loop:
754
        push    edi
3565 hidnplayr 755
        call    [eax + SOCKET.rcv_proc]
3704 hidnplayr 756
        pop     edi
3545 hidnplayr 757
 
4219 hidnplayr 758
        test    [eax + SOCKET.state], SS_CANTRCVMORE
759
        jnz     .return
760
 
3704 hidnplayr 761
        cmp     ebx, EWOULDBLOCK
762
        jne     .return
763
 
764
        test    edi, MSG_DONTWAIT
765
        jnz     .return_err
766
 
767
;        test    [eax + SOCKET.options], SO_NONBLOCK
768
;        jnz     .return_err
769
 
770
        call    SOCKET_block
771
        jmp     .loop
772
 
773
 
774
  .invalid:
775
        push    EINVAL
776
        pop     ebx
777
  .return_err:
4219 hidnplayr 778
        mov     ecx, -1
3704 hidnplayr 779
  .return:
3673 hidnplayr 780
        mov     [esp+20], ebx
4219 hidnplayr 781
        mov     [esp+32], ecx
3565 hidnplayr 782
        ret
3545 hidnplayr 783
 
3565 hidnplayr 784
 
3658 hidnplayr 785
 
3704 hidnplayr 786
 
787
 
3545 hidnplayr 788
align 4
789
SOCKET_receive_dgram:
3704 hidnplayr 790
 
3556 hidnplayr 791
        DEBUGF  DEBUG_NETWORK_VERBOSE, "SOCKET_receive: DGRAM\n"
3545 hidnplayr 792
 
3704 hidnplayr 793
        mov     ebx, esi                                        ; bufferlength
3545 hidnplayr 794
 
3704 hidnplayr 795
        get_from_queue (eax + SOCKET_QUEUE_LOCATION), SOCKET_QUEUE_SIZE, sizeof.socket_queue_entry, .wouldblock ; sets esi only on success.
3545 hidnplayr 796
        mov     ecx, [esi + socket_queue_entry.data_size]
3556 hidnplayr 797
        DEBUGF  DEBUG_NETWORK_VERBOSE, "SOCKET_receive: %u bytes data\n", ecx
3545 hidnplayr 798
 
3704 hidnplayr 799
        cmp     ecx, ebx                                        ; If data segment does not fit in applications buffer, abort
3545 hidnplayr 800
        ja      .too_small
801
 
4219 hidnplayr 802
        push    eax ecx
3545 hidnplayr 803
        push    [esi + socket_queue_entry.buf_ptr]              ; save the buffer addr so we can clear it later
804
        mov     esi, [esi + socket_queue_entry.data_ptr]
3556 hidnplayr 805
        DEBUGF  DEBUG_NETWORK_VERBOSE, "SOCKET_receive: Source buffer=%x real addr=%x\n", [esp], esi
3545 hidnplayr 806
 
3704 hidnplayr 807
; copy the data from kernel buffer to application buffer
808
        mov     edi, edx                                        ; bufferaddr
3545 hidnplayr 809
        shr     ecx, 1
810
        jnc     .nb
811
        movsb
812
  .nb:
813
        shr     ecx, 1
814
        jnc     .nw
815
        movsw
816
  .nw:
817
        test    ecx, ecx
818
        jz      .nd
3711 clevermous 819
        rep movsd
3545 hidnplayr 820
  .nd:
821
 
3861 hidnplayr 822
        call    NET_packet_free
4219 hidnplayr 823
        pop     ecx eax                                         ; return number of bytes copied to application
3704 hidnplayr 824
        xor     ebx, ebx
3545 hidnplayr 825
        ret
826
 
827
  .too_small:
4219 hidnplayr 828
        mov     ecx, -1
3704 hidnplayr 829
        push    EMSGSIZE
830
        pop     ebx
3565 hidnplayr 831
        ret
3545 hidnplayr 832
 
3658 hidnplayr 833
  .wouldblock:
3704 hidnplayr 834
        push    EWOULDBLOCK
835
        pop     ebx
3658 hidnplayr 836
        ret
3545 hidnplayr 837
 
3658 hidnplayr 838
 
3704 hidnplayr 839
 
3545 hidnplayr 840
align 4
841
SOCKET_receive_local:
842
 
843
        ; does this socket have a PID yet?
844
        cmp     [eax + SOCKET.PID], 0
845
        jne     @f
846
 
847
        ; Change PID to that of current process
848
        mov     ebx, [TASK_BASE]
849
        mov     ebx, [ebx + TASKDATA.pid]
850
        mov     [eax + SOCKET.PID], ebx
3704 hidnplayr 851
        mov     [eax + SOCKET.TID], ebx                         ; currently TID = PID in kolibrios :(
3545 hidnplayr 852
      @@:
853
 
854
        mov     [eax + SOCKET.rcv_proc], SOCKET_receive_stream
855
 
3704 hidnplayr 856
; ... continue to SOCKET_receive_stream
857
 
3545 hidnplayr 858
align 4
859
SOCKET_receive_stream:
860
 
3556 hidnplayr 861
        DEBUGF  DEBUG_NETWORK_VERBOSE, "SOCKET_receive: STREAM\n"
3545 hidnplayr 862
 
3704 hidnplayr 863
        cmp     [eax + STREAM_SOCKET.rcv + RING_BUFFER.size], 0
864
        je      .wouldblock
865
 
866
        test    edi, MSG_PEEK
867
        jnz     .peek
868
 
3545 hidnplayr 869
        mov     ecx, esi
870
        mov     edi, edx
871
        xor     edx, edx
872
 
4219 hidnplayr 873
        push    eax
3545 hidnplayr 874
        add     eax, STREAM_SOCKET.rcv
3704 hidnplayr 875
        call    SOCKET_ring_read                                ; copy data from kernel buffer to application buffer
876
        call    SOCKET_ring_free                                ; free read memory
4219 hidnplayr 877
        pop     eax
3545 hidnplayr 878
 
3704 hidnplayr 879
        xor     ebx, ebx                                        ; errorcode = 0 (no error)
3545 hidnplayr 880
        ret
881
 
3704 hidnplayr 882
  .wouldblock:
883
        push    EWOULDBLOCK
884
        pop     ebx
4219 hidnplayr 885
        xor     ecx, ecx
3704 hidnplayr 886
        ret
887
 
3545 hidnplayr 888
  .peek:
4219 hidnplayr 889
        mov     ecx, [eax + STREAM_SOCKET.rcv + RING_BUFFER.size]
3704 hidnplayr 890
        xor     ebx, ebx
3545 hidnplayr 891
        ret
892
 
893
 
894
;-----------------------------------------------------------------
895
;
896
; SOCKET_send
897
;
898
;
899
;  IN:  socket number in ecx
900
;       pointer to data in edx
901
;       datalength in esi
902
;       flags in edi
903
;  OUT: -1 on error
904
;
905
;-----------------------------------------------------------------
906
align 4
907
SOCKET_send:
908
 
3556 hidnplayr 909
        DEBUGF  DEBUG_NETWORK_VERBOSE, "SOCKET_send: socknum=%u data ptr=%x length=%u flags=%x\n", ecx, edx, esi, edi
3545 hidnplayr 910
 
911
        call    SOCKET_num_to_ptr
3658 hidnplayr 912
        jz      .invalid
3545 hidnplayr 913
 
914
        mov     ecx, esi
915
        mov     esi, edx
916
 
917
        jmp     [eax + SOCKET.snd_proc]
918
 
3658 hidnplayr 919
  .invalid:
3673 hidnplayr 920
        mov     dword[esp+20], EINVAL
3658 hidnplayr 921
        mov     dword[esp+32], -1
922
        ret
3545 hidnplayr 923
 
3658 hidnplayr 924
 
3545 hidnplayr 925
align 4
926
SOCKET_send_udp:
927
 
3556 hidnplayr 928
        DEBUGF  DEBUG_NETWORK_VERBOSE, "SOCKET_send: UDP\n"
3545 hidnplayr 929
 
930
        mov     [esp+32], ecx
931
        call    UDP_output
932
        cmp     eax, -1
3658 hidnplayr 933
        je      .error
3545 hidnplayr 934
        ret
935
 
3658 hidnplayr 936
  .error:
937
        mov     dword[esp+32], -1
3673 hidnplayr 938
        mov     dword[esp+20], EMSGSIZE ; FIXME: UDP_output should return error codes!
3658 hidnplayr 939
        ret
3545 hidnplayr 940
 
3658 hidnplayr 941
 
3545 hidnplayr 942
align 4
943
SOCKET_send_tcp:
944
 
3556 hidnplayr 945
        DEBUGF  DEBUG_NETWORK_VERBOSE, "SOCKET_send: TCP\n"
3545 hidnplayr 946
 
947
        push    eax
948
        add     eax, STREAM_SOCKET.snd
949
        call    SOCKET_ring_write
950
        pop     eax
951
 
952
        mov     [esp+32], ecx
3658 hidnplayr 953
        mov     [eax + SOCKET.errorcode], 0
954
        push    eax
955
        call    TCP_output              ; FIXME: this doesnt look pretty, does it?
956
        pop     eax
957
        mov     eax, [eax + SOCKET.errorcode]
3673 hidnplayr 958
        mov     [esp+20], eax
3545 hidnplayr 959
        ret
960
 
961
 
962
align 4
963
SOCKET_send_ip:
964
 
3556 hidnplayr 965
        DEBUGF  DEBUG_NETWORK_VERBOSE, "SOCKET_send: IPv4\n"
3545 hidnplayr 966
 
967
        mov     [esp+32], ecx
3658 hidnplayr 968
        call    IPv4_output_raw         ; FIXME: IPv4_output_raw should return error codes!
3545 hidnplayr 969
        cmp     eax, -1
3658 hidnplayr 970
        je      .error
3545 hidnplayr 971
        ret
972
 
3658 hidnplayr 973
  .error:
974
        mov     dword[esp+32], -1
3673 hidnplayr 975
        mov     dword[esp+20], EMSGSIZE
3658 hidnplayr 976
        ret
3545 hidnplayr 977
 
3658 hidnplayr 978
 
3545 hidnplayr 979
align 4
980
SOCKET_send_icmp:
981
 
3556 hidnplayr 982
        DEBUGF  DEBUG_NETWORK_VERBOSE, "SOCKET_send: ICMP\n"
3545 hidnplayr 983
 
984
        mov     [esp+32], ecx
3658 hidnplayr 985
        call    ICMP_output_raw         ; FIXME: errorcodes
3545 hidnplayr 986
        cmp     eax, -1
3658 hidnplayr 987
        je      .error
3545 hidnplayr 988
        ret
989
 
3658 hidnplayr 990
  .error:
991
        mov     dword[esp+32], -1
3673 hidnplayr 992
        mov     dword[esp+20], EMSGSIZE
3658 hidnplayr 993
        ret
3545 hidnplayr 994
 
3658 hidnplayr 995
 
3545 hidnplayr 996
align 4
997
SOCKET_send_pppoe:
998
 
3556 hidnplayr 999
        DEBUGF  DEBUG_NETWORK_VERBOSE, "SOCKET_send: PPPoE\n"
3545 hidnplayr 1000
 
1001
        mov     [esp+32], ecx
1002
        mov     ebx, [eax + SOCKET.device]
1003
 
3658 hidnplayr 1004
        call    PPPoE_discovery_output  ; FIXME: errorcodes
3545 hidnplayr 1005
        cmp     eax, -1
3658 hidnplayr 1006
        je      .error
3545 hidnplayr 1007
        ret
1008
 
3658 hidnplayr 1009
  .error:
1010
        mov     dword[esp+32], -1
3673 hidnplayr 1011
        mov     dword[esp+20], EMSGSIZE
3658 hidnplayr 1012
        ret
3545 hidnplayr 1013
 
1014
 
3658 hidnplayr 1015
 
3545 hidnplayr 1016
align 4
1017
SOCKET_send_local:
1018
 
1019
        ; does this socket have a PID yet?
1020
        cmp     [eax + SOCKET.PID], 0
1021
        jne     @f
1022
 
1023
        ; Change PID to that of current process
1024
        mov     ebx, [TASK_BASE]
1025
        mov     ebx, [ebx + TASKDATA.pid]
1026
        mov     [eax + SOCKET.PID], ebx
1027
        mov     [eax + SOCKET.TID], ebx         ; currently TID = PID in kolibrios :(
1028
      @@:
1029
        mov     [eax + SOCKET.snd_proc], SOCKET_send_local_
1030
 
1031
align 4
1032
SOCKET_send_local_:
1033
 
3556 hidnplayr 1034
        DEBUGF  DEBUG_NETWORK_VERBOSE, "SOCKET_send: LOCAL\n"
3545 hidnplayr 1035
 
1036
        ; get the other side's socket and check if it still exists
1037
        mov     eax, [eax + SOCKET.device]
1038
        call    SOCKET_check
3658 hidnplayr 1039
        jz      .invalid
3545 hidnplayr 1040
 
1041
        ; allright, shove in the data!
1042
        push    eax
1043
        add     eax, STREAM_SOCKET.rcv
1044
        call    SOCKET_ring_write
1045
        pop     eax
1046
 
1047
        ; return the number of written bytes (or errorcode) to application
1048
        mov     [esp+32], ecx
1049
 
1050
        ; and notify the other end
1051
        call    SOCKET_notify
1052
 
1053
        ret
1054
 
3658 hidnplayr 1055
  .invalid:
1056
        mov     dword[esp+32], -1
3673 hidnplayr 1057
        mov     dword[esp+20], EINVAL
3658 hidnplayr 1058
        ret
3545 hidnplayr 1059
 
3658 hidnplayr 1060
 
3545 hidnplayr 1061
;-----------------------------------------------------------------
1062
;
1063
; SOCKET_get_options
1064
;
1065
;  IN:  ecx = socket number
1066
;       edx = pointer to the options:
1067
;               dd      level, optname, optval, optlen
1068
;  OUT: -1 on error
1069
;
1070
; At moment, uses only pseudo-optname -2 for get last_ack_number for TCP.
1071
; TODO: find best way to notify that send()'ed data were acknowledged
1072
; Also pseudo-optname -3 is valid and returns socket state, one of TCPS_*.
1073
;
1074
;-----------------------------------------------------------------
1075
align 4
1076
SOCKET_get_opt:
1077
 
3556 hidnplayr 1078
        DEBUGF  DEBUG_NETWORK_VERBOSE, "SOCKET_get_opt\n"
3545 hidnplayr 1079
 
1080
        call    SOCKET_num_to_ptr
3658 hidnplayr 1081
        jz      .invalid
3545 hidnplayr 1082
 
1083
        cmp     dword [edx], IP_PROTO_TCP
3658 hidnplayr 1084
        jne     .invalid
3545 hidnplayr 1085
        cmp     dword [edx+4], -2
1086
        je      @f
1087
        cmp     dword [edx+4], -3
3658 hidnplayr 1088
        jne     .invalid
3545 hidnplayr 1089
@@:
1090
;        mov     eax, [edx+12]
1091
;        test    eax, eax
1092
;        jz      .fail
1093
;        cmp     dword [eax], 4
1094
;        mov     dword [eax], 4
1095
;        jb      .fail
1096
;        stdcall net_socket_num_to_addr, ecx
1097
;        test    eax, eax
1098
;        jz      .fail
1099
;        ; todo: check that eax is really TCP socket
1100
;        mov     ecx, [eax + TCP_SOCKET.last_ack_number]
1101
;        cmp     dword [edx+4], -2
1102
;        jz      @f
1103
;        mov     ecx, [eax + TCP_SOCKET.state]
1104
@@:
1105
        mov     eax, [edx+8]
1106
        test    eax, eax
1107
        jz      @f
1108
        mov     [eax], ecx
1109
@@:
1110
        mov     dword [esp+32], 0
1111
        ret
1112
 
3658 hidnplayr 1113
  .invalid:
1114
        mov     dword[esp+32], -1
3673 hidnplayr 1115
        mov     dword[esp+20], EINVAL
3658 hidnplayr 1116
        ret
3545 hidnplayr 1117
 
1118
 
3658 hidnplayr 1119
 
3545 hidnplayr 1120
;-----------------------------------------------------------------
1121
;
1122
; SOCKET_set_options
1123
;
1124
;  IN:  ecx = socket number
1125
;       edx = pointer to the options:
1126
;               dd      level, optname, optlen, optval
1127
;  OUT: -1 on error
1128
;
1129
;-----------------------------------------------------------------
1130
align 4
1131
SOCKET_set_opt:
1132
 
3556 hidnplayr 1133
        DEBUGF  DEBUG_NETWORK_VERBOSE, "SOCKET_set_opt\n"
3545 hidnplayr 1134
 
1135
        call    SOCKET_num_to_ptr
3658 hidnplayr 1136
        jz      .invalid
3545 hidnplayr 1137
 
1138
        cmp     dword [edx], SOL_SOCKET
3658 hidnplayr 1139
        jne     .invalid
3545 hidnplayr 1140
 
1141
        cmp     dword [edx+4], SO_BINDTODEVICE
1142
        je      .bind
1143
 
3658 hidnplayr 1144
  .invalid:
1145
        mov     dword[esp+32], -1
3673 hidnplayr 1146
        mov     dword[esp+20], EINVAL
3658 hidnplayr 1147
        ret
3545 hidnplayr 1148
 
1149
  .bind:
3658 hidnplayr 1150
        cmp     dword[edx+8], 0
3545 hidnplayr 1151
        je      .unbind
1152
 
3658 hidnplayr 1153
        movzx   edx, byte[edx + 9]
3600 hidnplayr 1154
        cmp     edx, NET_DEVICES_MAX
3658 hidnplayr 1155
        ja      .invalid
3545 hidnplayr 1156
 
1157
        mov     edx, [NET_DRV_LIST + 4*edx]
1158
        test    edx, edx
3658 hidnplayr 1159
        jz      .already
3545 hidnplayr 1160
        mov     [eax + SOCKET.device], edx
1161
 
3556 hidnplayr 1162
        DEBUGF  DEBUG_NETWORK_VERBOSE, "SOCKET_set_opt: Bound socket %x to device %x\n",eax, edx
3545 hidnplayr 1163
 
3658 hidnplayr 1164
        mov     dword[esp+32], 0        ; success!
3545 hidnplayr 1165
        ret
1166
 
1167
  .unbind:
1168
        mov     [eax + SOCKET.device], 0
1169
 
3658 hidnplayr 1170
        mov     dword[esp+32], 0        ; success!
3545 hidnplayr 1171
        ret
1172
 
3658 hidnplayr 1173
  .already:
3673 hidnplayr 1174
        mov     dword[esp+20], EALREADY
3658 hidnplayr 1175
        mov     dword[esp+32], -1
1176
        ret
3545 hidnplayr 1177
 
1178
 
3658 hidnplayr 1179
 
1180
 
3545 hidnplayr 1181
;-----------------------------------------------------------------
1182
;
1183
; SOCKET_pair
1184
;
1185
; Allocates a pair of linked LOCAL domain sockets
1186
;
1187
; IN: /
1188
; OUT: eax is socket1 num, -1 on error
1189
;      ebx is socket2 num
1190
;
1191
;-----------------------------------------------------------------
1192
align 4
1193
SOCKET_pair:
1194
 
3556 hidnplayr 1195
        DEBUGF  DEBUG_NETWORK_VERBOSE, "SOCKET_pair\n"
3545 hidnplayr 1196
 
1197
        call    SOCKET_alloc
3658 hidnplayr 1198
        jz      .nomem1
3545 hidnplayr 1199
        mov     [esp+32], edi   ; application's eax
1200
 
1201
        mov     [eax + SOCKET.Domain], AF_LOCAL
1202
        mov     [eax + SOCKET.Type], SOCK_STREAM
1203
        mov     [eax + SOCKET.Protocol], 0              ;;; CHECKME
1204
        mov     [eax + SOCKET.snd_proc], SOCKET_send_local
1205
        mov     [eax + SOCKET.rcv_proc], SOCKET_receive_local
1206
        mov     [eax + SOCKET.PID], 0
1207
        mov     ebx, eax
1208
 
1209
        call    SOCKET_alloc
3658 hidnplayr 1210
        jz      .nomem2
3673 hidnplayr 1211
        mov     [esp+20], edi   ; application's ebx
3545 hidnplayr 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
 
3658 hidnplayr 1233
  .nomem2:
3545 hidnplayr 1234
        mov     eax, ebx
1235
        call    SOCKET_free
3658 hidnplayr 1236
  .nomem1:
1237
        mov     dword[esp+32], -1
1238
        mov     dword[esp+28], ENOMEM
1239
        ret
3545 hidnplayr 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
 
3556 hidnplayr 1257
        DEBUGF  DEBUG_NETWORK_VERBOSE, "SOCKET_debug\n"
3545 hidnplayr 1258
 
1259
        mov     edi, edx
1260
 
1261
        test    ecx, ecx
1262
        jz      .returnall
1263
 
1264
        call    SOCKET_num_to_ptr
3658 hidnplayr 1265
        jz      .invalid
3545 hidnplayr 1266
 
1267
        mov     esi, eax
1268
        mov     ecx, SOCKETBUFFSIZE/4
3711 clevermous 1269
        rep movsd
3545 hidnplayr 1270
 
3658 hidnplayr 1271
        mov     dword[esp+32], 0
3545 hidnplayr 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
3658 hidnplayr 1286
        mov     dword[esp+32], eax
1287
        ret
3545 hidnplayr 1288
 
3658 hidnplayr 1289
  .invalid:
1290
        mov     dword[esp+32], -1
1291
        mov     dword[esp+28], EINVAL
3545 hidnplayr 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
 
3556 hidnplayr 1310
        DEBUGF  DEBUG_NETWORK_VERBOSE, "SOCKET_find_port\n"
3545 hidnplayr 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
 
3556 hidnplayr 1371
        DEBUGF  DEBUG_NETWORK_VERBOSE, "SOCKET_check_port: "
3545 hidnplayr 1372
 
3647 hidnplayr 1373
        pusha
1374
        mov     ecx, socket_mutex
1375
        call    mutex_lock
1376
        popa
1377
 
3545 hidnplayr 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
 
3647 hidnplayr 1396
        pusha
1397
        mov     ecx, socket_mutex
1398
        call    mutex_unlock
1399
        popa
1400
 
3556 hidnplayr 1401
        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 1402
        ret
1403
 
1404
  .port_ok:
3647 hidnplayr 1405
        pusha
1406
        mov     ecx, socket_mutex
1407
        call    mutex_unlock
1408
        popa
1409
 
3556 hidnplayr 1410
        DEBUGF  DEBUG_NETWORK_VERBOSE, "local port %x is free\n", bx         ; FIXME: find a way to print big endian values with debugf
3545 hidnplayr 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
 
3556 hidnplayr 1437
        DEBUGF  DEBUG_NETWORK_VERBOSE, "SOCKET_input: socket=%x, data=%x size=%u\n", eax, esi, ecx
3545 hidnplayr 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
 
3556 hidnplayr 1445
        DEBUGF  DEBUG_NETWORK_VERBOSE, "SOCKET_input: success\n"
3545 hidnplayr 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:
3556 hidnplayr 1456
        DEBUGF  DEBUG_NETWORK_VERBOSE, "SOCKET_input: socket %x is full!\n", eax
3545 hidnplayr 1457
 
1458
        pusha
1459
        lea     ecx, [eax + SOCKET.mutex]
1460
        call    mutex_unlock
1461
        popa
1462
 
3861 hidnplayr 1463
        call    NET_packet_free
3545 hidnplayr 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
 
3556 hidnplayr 1483
        DEBUGF  DEBUG_NETWORK_VERBOSE, "SOCKET_ring_created: %x\n", eax
3545 hidnplayr 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
 
3556 hidnplayr 1517
        DEBUGF  DEBUG_NETWORK_VERBOSE, "SOCKET_ring_write: ringbuff=%x ptr=%x size=%u\n", eax, esi, ecx
3545 hidnplayr 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]
3556 hidnplayr 1533
        DEBUGF  DEBUG_NETWORK_VERBOSE, "SOCKET_ring_write: %u bytes from %x to %x\n", ecx, esi, edi
3545 hidnplayr 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
3711 clevermous 1560
        rep movsd
3545 hidnplayr 1561
  .nd:
1562
        pop     ecx
1563
 
1564
; unlock mutex
1565
        push    eax ecx
1566
        lea     ecx, [eax + RING_BUFFER.mutex]
1567
        call    mutex_unlock                                    ; TODO: check what registers this function actually destroys
1568
        pop     ecx eax
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
 
3556 hidnplayr 1591
        DEBUGF  DEBUG_NETWORK_VERBOSE, "SOCKET_ring_read: ringbuff=%x ptr=%x size=%u offset=%x\n", eax, edi, ecx, edx
3545 hidnplayr 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:
3556 hidnplayr 1614
        DEBUGF  DEBUG_NETWORK_VERBOSE, "SOCKET_ring_read: %u bytes from %x to %x\n", ecx, esi, edi
3545 hidnplayr 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
3711 clevermous 1626
        rep movsd
3545 hidnplayr 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
 
3556 hidnplayr 1637
        DEBUGF  DEBUG_NETWORK_VERBOSE, "SOCKET_ring_read: no data at all!\n"
3545 hidnplayr 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
 
3556 hidnplayr 1661
        DEBUGF  DEBUG_NETWORK_VERBOSE, "SOCKET_ring_free: %u bytes from ring %x\n", ecx, eax
3545 hidnplayr 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..
3556 hidnplayr 1686
        DEBUGF  DEBUG_NETWORK_VERBOSE, "SOCKET_ring_free: buffer=%x error!\n", eax
3545 hidnplayr 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
3674 hidnplayr 1705
;  OUT: eax = unchanged
3545 hidnplayr 1706
;
1707
;-----------------------------------------------------------------
1708
align 4
1709
SOCKET_block:
1710
 
3556 hidnplayr 1711
        DEBUGF  DEBUG_NETWORK_VERBOSE, "SOCKET_block: %x\n", eax
3545 hidnplayr 1712
 
1713
        pushf
3674 hidnplayr 1714
        push    eax
3545 hidnplayr 1715
        cli
1716
 
1717
        ; Set the 'socket is blocked' flag
1718
        or      [eax + SOCKET.state], SS_BLOCKED
1719
 
1720
        ; Suspend the thread
1721
        push    edx
1722
        mov     edx, [TASK_BASE]
1723
        mov     [edx + TASKDATA.state], 1               ; Suspended
1724
 
1725
        ; Remember the thread ID so we can wake it up again
1726
        mov     edx, [edx + TASKDATA.pid]
3556 hidnplayr 1727
        DEBUGF  DEBUG_NETWORK_VERBOSE, "SOCKET_block: suspending thread: %u\n", edx
3545 hidnplayr 1728
        mov     [eax + SOCKET.TID], edx
1729
        pop     edx
1730
 
1731
        call    change_task
3674 hidnplayr 1732
        pop     eax
3545 hidnplayr 1733
        popf
1734
 
3556 hidnplayr 1735
        DEBUGF  DEBUG_NETWORK_VERBOSE, "SOCKET_block: continueing\n"
3545 hidnplayr 1736
 
1737
        ret
1738
 
1739
 
1740
;-----------------------------------------------------------------
1741
;
1742
; SOCKET_notify
1743
;
1744
; notify's the owner of a socket that something happened
1745
;
1746
;  IN:  eax = socket ptr
3674 hidnplayr 1747
;  OUT: eax = unchanged
3545 hidnplayr 1748
;
1749
;-----------------------------------------------------------------
1750
align 4
1751
SOCKET_notify:
1752
 
3556 hidnplayr 1753
        DEBUGF  DEBUG_NETWORK_VERBOSE, "SOCKET_notify: %x\n", eax
3545 hidnplayr 1754
 
1755
        call    SOCKET_check
1756
        jz      .error
1757
 
1758
        test    [eax + SOCKET.state], SS_BLOCKED
1759
        jnz     .unblock
1760
 
3704 hidnplayr 1761
;        test    [eax + SOCKET.options], SO_NONBLOCK
1762
;        jz      .error
3545 hidnplayr 1763
 
1764
        push    eax ecx esi
1765
 
1766
; socket exists and is of non blocking type.
1767
; We'll try to flag an event to the thread
1768
 
1769
        mov     eax, [eax + SOCKET.TID]
1770
        test    eax, eax
1771
        jz      .done
1772
        mov     ecx, 1
1773
        mov     esi, TASK_DATA + TASKDATA.pid
1774
 
1775
  .next_pid:
1776
        cmp     [esi], eax
1777
        je      .found_pid
1778
        inc     ecx
1779
        add     esi, 0x20
1780
        cmp     ecx, [TASK_COUNT]
1781
        jbe     .next_pid
1782
; PID not found, TODO: close socket!
1783
        jmp     .done
1784
 
1785
  .found_pid:
1786
        shl     ecx, 8
1787
        or      [ecx + SLOT_BASE + APPDATA.event_mask], EVENT_NETWORK
1788
 
3817 hidnplayr 1789
        DEBUGF  DEBUG_NETWORK_VERBOSE, "SOCKET_notify: poking thread %u!\n", eax
3545 hidnplayr 1790
        jmp     .done
1791
 
1792
  .unblock:
1793
        push    eax ecx esi
1794
        ; Clear the 'socket is blocked' flag
1795
        and     [eax + SOCKET.state], not SS_BLOCKED
1796
 
1797
        ; Find the thread's TASK_DATA
1798
        mov     eax, [eax + SOCKET.TID]
1799
        test    eax, eax
1800
        jz      .error
1801
        xor     ecx, ecx
1802
        inc     ecx
1803
        mov     esi, TASK_DATA
1804
  .next:
1805
        cmp     [esi + TASKDATA.pid], eax
1806
        je      .found
1807
        inc     ecx
1808
        add     esi, 0x20
1809
        cmp     ecx, [TASK_COUNT]
1810
        jbe     .next
1811
        jmp     .error
1812
  .found:
1813
 
1814
        ; Run the thread
1815
        mov     [esi + TASKDATA.state], 0       ; Running
3556 hidnplayr 1816
        DEBUGF  DEBUG_NETWORK_VERBOSE, "SOCKET_notify: Unblocked socket!\n"
3545 hidnplayr 1817
 
1818
  .done:
1819
        pop     esi ecx eax
1820
 
1821
  .error:
1822
        ret
1823
 
1824
 
1825
;--------------------------------------------------------------------
1826
;
1827
; SOCKET_alloc
1828
;
1829
; Allocate memory for socket data and put new socket into the list
1830
; Newly created socket is initialized with calling PID and number and
1831
; put into beginning of list (which is a fastest way).
1832
;
1833
; IN:  /
1834
; OUT: eax = 0 on error, socket ptr otherwise
1835
;      edi = socket number
1836
;       ZF = cleared on error
1837
;
1838
;--------------------------------------------------------------------
1839
align 4
1840
SOCKET_alloc:
1841
 
1842
        push    ebx
1843
 
1844
        stdcall kernel_alloc, SOCKETBUFFSIZE
3556 hidnplayr 1845
        DEBUGF  DEBUG_NETWORK_VERBOSE, "SOCKET_alloc: ptr=%x\n", eax
3545 hidnplayr 1846
        or      eax, eax
1847
        jz      .exit
1848
 
1849
; zero-initialize allocated memory
1850
        push    eax
1851
        mov     edi, eax
1852
        mov     ecx, SOCKETBUFFSIZE / 4
1853
        xor     eax, eax
3711 clevermous 1854
        rep stosd
3545 hidnplayr 1855
        pop     eax
1856
 
1857
; set send-and receive procedures to return -1
3658 hidnplayr 1858
        mov     [eax + SOCKET.snd_proc], .not_yet
1859
        mov     [eax + SOCKET.rcv_proc], .not_yet
3545 hidnplayr 1860
 
3647 hidnplayr 1861
        pusha
1862
        mov     ecx, socket_mutex
1863
        call    mutex_lock
1864
        popa
1865
 
3545 hidnplayr 1866
; find first free socket number and use it
1867
        mov     edi, [last_socket_num]
1868
  .next_socket_number:
1869
        inc     edi
1870
        jz      .next_socket_number     ; avoid socket nr 0
1871
        cmp     edi, -1
1872
        je      .next_socket_number     ; avoid socket nr -1
1873
        mov     ebx, net_sockets
1874
  .next_socket:
1875
        mov     ebx, [ebx + SOCKET.NextPtr]
1876
        test    ebx, ebx
1877
        jz      .last_socket
1878
 
1879
        cmp     [ebx + SOCKET.Number], edi
1880
        jne     .next_socket
1881
        jmp     .next_socket_number
1882
 
1883
  .last_socket:
1884
        mov     [last_socket_num], edi
1885
        mov     [eax + SOCKET.Number], edi
3556 hidnplayr 1886
        DEBUGF  DEBUG_NETWORK_VERBOSE, "SOCKET_alloc: number=%u\n", edi
3545 hidnplayr 1887
 
1888
; Fill in PID
1889
        mov     ebx, [TASK_BASE]
1890
        mov     ebx, [ebx + TASKDATA.pid]
1891
        mov     [eax + SOCKET.PID], ebx
1892
        mov     [eax + SOCKET.TID], ebx         ; currently TID = PID in kolibrios :(
1893
 
1894
; init mutex
1895
        pusha
1896
        lea     ecx, [eax + SOCKET.mutex]
1897
        call    mutex_init
1898
        popa
1899
 
1900
; add socket to the list by re-arranging some pointers
1901
        mov     ebx, [net_sockets + SOCKET.NextPtr]
1902
 
1903
        mov     [eax + SOCKET.PrevPtr], net_sockets
1904
        mov     [eax + SOCKET.NextPtr], ebx
1905
 
1906
        test    ebx, ebx
1907
        jz      @f
1908
 
1909
        pusha
1910
        lea     ecx, [ebx + SOCKET.mutex]
1911
        call    mutex_lock
1912
        popa
1913
 
1914
        mov     [ebx + SOCKET.PrevPtr], eax
1915
 
1916
        pusha
1917
        lea     ecx, [ebx + SOCKET.mutex]
1918
        call    mutex_unlock
1919
        popa
1920
       @@:
1921
 
1922
        mov     [net_sockets + SOCKET.NextPtr], eax
1923
        or      eax, eax                ; used to clear zero flag
3647 hidnplayr 1924
 
1925
        pusha
1926
        mov     ecx, socket_mutex
1927
        call    mutex_unlock
1928
        popa
1929
 
3545 hidnplayr 1930
  .exit:
1931
        pop     ebx
1932
 
1933
        ret
1934
 
3658 hidnplayr 1935
  .not_yet:
3673 hidnplayr 1936
        mov     dword[esp+20], ENOTCONN
3658 hidnplayr 1937
        mov     dword[esp+32], -1
1938
        ret
3545 hidnplayr 1939
 
3658 hidnplayr 1940
 
3545 hidnplayr 1941
;----------------------------------------------------
1942
;
1943
; SOCKET_free
1944
;
1945
; Free socket data memory and remove socket from the list
3884 hidnplayr 1946
; Caller should lock and unlock socket_mutex
3545 hidnplayr 1947
;
1948
; IN:  eax = socket ptr
1949
; OUT: /
1950
;
1951
;----------------------------------------------------
1952
align 4
1953
SOCKET_free:
1954
 
3556 hidnplayr 1955
        DEBUGF  DEBUG_NETWORK_VERBOSE, "SOCKET_free: %x\n", eax
3545 hidnplayr 1956
 
1957
        call    SOCKET_check
1958
        jz      .error
1959
 
1960
        push    ebx
1961
 
1962
        pusha
1963
        lea     ecx, [eax + SOCKET.mutex]
1964
        call    mutex_lock
1965
        popa
1966
 
1967
        cmp     [eax + SOCKET.Domain], AF_INET4
1968
        jnz     .no_tcp
1969
 
1970
        cmp     [eax + SOCKET.Protocol], IP_PROTO_TCP
1971
        jnz     .no_tcp
1972
 
1973
        mov     ebx, eax
1974
        stdcall kernel_free, [ebx + STREAM_SOCKET.rcv.start_ptr]
1975
        stdcall kernel_free, [ebx + STREAM_SOCKET.snd.start_ptr]
1976
        mov     eax, ebx
1977
  .no_tcp:
1978
 
3652 hidnplayr 1979
        DEBUGF  DEBUG_NETWORK_VERBOSE, "SOCKET_free: freeing socket %x\n", eax
3545 hidnplayr 1980
        push    eax                             ; this will be passed to kernel_free
1981
        mov     ebx, [eax + SOCKET.NextPtr]
1982
        mov     eax, [eax + SOCKET.PrevPtr]
1983
 
3556 hidnplayr 1984
        DEBUGF  DEBUG_NETWORK_VERBOSE, "SOCKET_free: linking socket %x to socket %x\n", eax, ebx
3545 hidnplayr 1985
 
1986
        test    eax, eax
1987
        jz      @f
1988
        mov     [eax + SOCKET.NextPtr], ebx
1989
       @@:
1990
 
1991
        test    ebx, ebx
1992
        jz      @f
1993
        mov     [ebx + SOCKET.PrevPtr], eax
1994
       @@:
1995
 
1996
        call    kernel_free
1997
        pop     ebx
1998
 
3652 hidnplayr 1999
        DEBUGF  DEBUG_NETWORK_VERBOSE, "SOCKET_free: success!\n"
2000
 
2001
  .error:
3545 hidnplayr 2002
        ret
2003
 
2004
;------------------------------------
2005
;
2006
; SOCKET_fork
2007
;
2008
; Create a child socket
2009
;
2010
; IN:  socket nr in ebx
2011
; OUT: child socket nr in eax
2012
;
2013
;-----------------------------------
2014
align 4
2015
SOCKET_fork:
2016
 
3556 hidnplayr 2017
        DEBUGF  DEBUG_NETWORK_VERBOSE, "SOCKET_fork: %x\n", ebx
3545 hidnplayr 2018
 
2019
; Exit if backlog queue is full
2020
        mov     eax, [ebx + SOCKET_QUEUE_LOCATION + queue.size]
2021
        cmp     ax, [ebx + SOCKET.backlog]
2022
        jae     .fail
2023
 
2024
; Allocate new socket
2025
        push    ebx
2026
        call    SOCKET_alloc
2027
        pop     ebx
2028
        jz      .fail
2029
 
2030
        push    eax
2031
        mov     esi, esp
2032
        add_to_queue (ebx + SOCKET_QUEUE_LOCATION), MAX_backlog, 4, .fail2
2033
        pop     eax
2034
 
2035
; Copy structure from current socket to new
3817 hidnplayr 2036
; We start at PID to preserve the socket num, 2 pointers and mutex
2037
; TID will be filled in later
3545 hidnplayr 2038
        lea     esi, [ebx + SOCKET.PID]
2039
        lea     edi, [eax + SOCKET.PID]
2040
        mov     ecx, (SOCKET_QUEUE_LOCATION - SOCKET.PID + 3)/4
3711 clevermous 2041
        rep movsd
3545 hidnplayr 2042
 
2043
        and     [eax + SOCKET.options], not SO_ACCEPTCON
2044
 
3817 hidnplayr 2045
; Notify owner of parent socket
2046
        push    eax
2047
        mov     eax, ebx
2048
        call    SOCKET_notify
2049
        pop     eax
2050
 
3545 hidnplayr 2051
        ret
2052
 
2053
  .fail2:
2054
        add     esp, 4+4+4
2055
  .fail:
3556 hidnplayr 2056
        DEBUGF  DEBUG_NETWORK_ERROR, "SOCKET_fork: failed\n"
3545 hidnplayr 2057
        xor     eax, eax
2058
        ret
2059
 
2060
 
2061
;---------------------------------------------------
2062
;
2063
; SOCKET_num_to_ptr
2064
;
2065
; Get socket structure address by its number
2066
;
2067
; IN:  ecx = socket number
2068
; OUT: eax = 0 on error, socket ptr otherwise
2069
;       ZF = set on error
2070
;
2071
;---------------------------------------------------
2072
align 4
2073
SOCKET_num_to_ptr:
2074
 
3556 hidnplayr 2075
        DEBUGF  DEBUG_NETWORK_VERBOSE, "SOCKET_num_to_ptr: num=%u ", ecx
3545 hidnplayr 2076
 
3647 hidnplayr 2077
        pusha
2078
        mov     ecx, socket_mutex
2079
        call    mutex_lock
2080
        popa
2081
 
3545 hidnplayr 2082
        mov     eax, net_sockets
2083
 
2084
  .next_socket:
2085
        mov     eax, [eax + SOCKET.NextPtr]
2086
        or      eax, eax
2087
        jz      .error
4219 hidnplayr 2088
                diff16 "tetten", 0, $
3545 hidnplayr 2089
        cmp     [eax + SOCKET.Number], ecx
2090
        jne     .next_socket
2091
 
2092
        test    eax, eax
2093
 
3647 hidnplayr 2094
        pusha
2095
        mov     ecx, socket_mutex
2096
        call    mutex_unlock
2097
        popa
2098
 
3556 hidnplayr 2099
        DEBUGF  DEBUG_NETWORK_VERBOSE, "ptr=%x\n", eax
3545 hidnplayr 2100
        ret
2101
 
2102
  .error:
3647 hidnplayr 2103
        pusha
2104
        mov     ecx, socket_mutex
2105
        call    mutex_unlock
2106
        popa
2107
 
3637 hidnplayr 2108
        DEBUGF  DEBUG_NETWORK_ERROR, "SOCKET_num_to_ptr: not found\n", eax
3545 hidnplayr 2109
        ret
2110
 
2111
 
2112
;---------------------------------------------------
2113
;
2114
; SOCKET_ptr_to_num
2115
;
2116
; Get socket number by its address
2117
;
2118
; IN:  eax = socket ptr
2119
; OUT: eax = 0 on error, socket num otherwise
2120
;       ZF = set on error
2121
;
2122
;---------------------------------------------------
2123
align 4
2124
SOCKET_ptr_to_num:
2125
 
3556 hidnplayr 2126
        DEBUGF  DEBUG_NETWORK_VERBOSE, "SOCKET_ptr_to_num: ptr=%x ", eax
3545 hidnplayr 2127
 
2128
        call    SOCKET_check
2129
        jz      .error
2130
 
2131
        mov     eax, [eax + SOCKET.Number]
2132
 
3556 hidnplayr 2133
        DEBUGF  DEBUG_NETWORK_VERBOSE, "num=%u\n", eax
3545 hidnplayr 2134
        ret
2135
 
2136
  .error:
3556 hidnplayr 2137
        DEBUGF  DEBUG_NETWORK_ERROR, "SOCKET_ptr_to_num: not found\n", eax
3545 hidnplayr 2138
        ret
2139
 
2140
 
2141
;---------------------------------------------------
2142
;
2143
; SOCKET_check
2144
;
2145
; checks if the given value is really a socket ptr
2146
;
2147
; IN:  eax = socket ptr
2148
; OUT: eax = 0 on error, unchanged otherwise
2149
;       ZF = set on error
2150
;
2151
;---------------------------------------------------
2152
align 4
2153
SOCKET_check:
2154
 
3556 hidnplayr 2155
        DEBUGF  DEBUG_NETWORK_VERBOSE, "SOCKET_check: %x\n", eax
3545 hidnplayr 2156
 
2157
        push    ebx
2158
        mov     ebx, net_sockets
2159
 
2160
  .next_socket:
2161
        mov     ebx, [ebx + SOCKET.NextPtr]
2162
        or      ebx, ebx
2163
        jz      .done
2164
        cmp     ebx, eax
2165
        jnz     .next_socket
2166
 
2167
  .done:
2168
        mov     eax, ebx
2169
        test    eax, eax
2170
        pop     ebx
2171
 
2172
        ret
2173
 
2174
 
2175
 
2176
;---------------------------------------------------
2177
;
2178
; SOCKET_check_owner
2179
;
2180
; checks if the caller application owns the socket
2181
;
2182
; IN:  eax = socket ptr
2183
; OUT:  ZF = true/false
2184
;
2185
;---------------------------------------------------
2186
align 4
2187
SOCKET_check_owner:
2188
 
3556 hidnplayr 2189
        DEBUGF  DEBUG_NETWORK_VERBOSE, "SOCKET_check_owner: %x\n", eax
3545 hidnplayr 2190
 
2191
        push    ebx
2192
        mov     ebx, [TASK_BASE]
2193
        mov     ebx, [ebx + TASKDATA.pid]
2194
        cmp     [eax + SOCKET.PID], ebx
3711 clevermous 2195
        pop     ebx
3545 hidnplayr 2196
 
2197
        ret
2198
 
2199
 
2200
 
2201
 
2202
;------------------------------------------------------
2203
;
2204
; SOCKET_process_end
2205
;
2206
; Kernel calls this function when a certain process ends
2207
; This function will check if the process had any open sockets
2208
; And update them accordingly
2209
;
2210
; IN:  edx = pid
2211
; OUT: /
2212
;
2213
;------------------------------------------------------
2214
align 4
2215
SOCKET_process_end:
2216
 
4056 hidnplayr 2217
        cmp     [net_sockets + SOCKET.NextPtr], 0       ; Are there any active sockets at all?
2218
        je      .quickret                               ; nope, exit immediately
2219
 
2220
; TODO: run the following code in another thread, to avoid deadlock
2221
 
3556 hidnplayr 2222
        DEBUGF  DEBUG_NETWORK_VERBOSE, "SOCKET_process_end: %x\n", edx
3545 hidnplayr 2223
 
3647 hidnplayr 2224
        pusha
2225
        mov     ecx, socket_mutex
2226
        call    mutex_lock
2227
        popa
2228
 
3545 hidnplayr 2229
        push    ebx
2230
        mov     ebx, net_sockets
2231
 
2232
  .next_socket:
2233
        mov     ebx, [ebx + SOCKET.NextPtr]
2234
  .next_socket_test:
2235
        test    ebx, ebx
2236
        jz      .done
2237
 
2238
        cmp     [ebx + SOCKET.PID], edx
2239
        jne     .next_socket
2240
 
3556 hidnplayr 2241
        DEBUGF  DEBUG_NETWORK_VERBOSE, "SOCKET_process_end: killing socket %x\n", ebx
3545 hidnplayr 2242
 
2243
        mov     [ebx + SOCKET.PID], 0
2244
        mov     eax, ebx
2245
        mov     ebx, [ebx + SOCKET.NextPtr]
3648 hidnplayr 2246
 
3545 hidnplayr 2247
        pusha
3652 hidnplayr 2248
        cmp     [eax + SOCKET.Domain], AF_INET4
2249
        jne     .free
2250
 
2251
        cmp     [eax + SOCKET.Protocol], IP_PROTO_TCP
2252
        jne     .free
2253
 
2254
        call    TCP_close
2255
        jmp     .closed
2256
 
2257
  .free:
2258
        call    SOCKET_free
2259
 
2260
  .closed:
3545 hidnplayr 2261
        popa
2262
        jmp     .next_socket_test
2263
 
2264
  .done:
2265
        pop     ebx
2266
 
3647 hidnplayr 2267
        pusha
2268
        mov     ecx, socket_mutex
2269
        call    mutex_unlock
2270
        popa
2271
 
4056 hidnplayr 2272
  .quickret:
3545 hidnplayr 2273
        ret
2274
 
2275
 
2276
 
2277
 
2278
;-----------------------------------------------------------------
2279
;
2280
; SOCKET_is_connecting
2281
;
2282
;  IN:  eax = socket ptr
2283
;  OUT: /
2284
;
2285
;-----------------------------------------------------------------
2286
 
2287
align 4
2288
SOCKET_is_connecting:
2289
 
3556 hidnplayr 2290
        DEBUGF  DEBUG_NETWORK_VERBOSE, "SOCKET_is_connecting: %x\n", eax
3545 hidnplayr 2291
 
4025 hidnplayr 2292
        and     [eax + SOCKET.state], not (SS_ISCONNECTED + SS_ISDISCONNECTING + SS_ISCONFIRMING)
2293
        or      [eax + SOCKET.state], SS_ISCONNECTING
3545 hidnplayr 2294
 
4025 hidnplayr 2295
        ret
3545 hidnplayr 2296
 
2297
 
2298
 
2299
;-----------------------------------------------------------------
2300
;
2301
; SOCKET_is_connected
2302
;
2303
;  IN:  eax = socket ptr
2304
;  OUT: /
2305
;
2306
;-----------------------------------------------------------------
2307
 
2308
align 4
2309
SOCKET_is_connected:
2310
 
3556 hidnplayr 2311
        DEBUGF  DEBUG_NETWORK_VERBOSE, "SOCKET_is_connected: %x\n", eax
3545 hidnplayr 2312
 
3674 hidnplayr 2313
        and     [eax + SOCKET.state], not (SS_ISCONNECTING + SS_ISDISCONNECTING + SS_ISCONFIRMING)
2314
        or      [eax + SOCKET.state], SS_ISCONNECTED
3545 hidnplayr 2315
 
2316
        jmp     SOCKET_notify
2317
 
2318
 
2319
 
2320
 
2321
;-----------------------------------------------------------------
2322
;
2323
; SOCKET_is_disconnecting
2324
;
2325
;  IN:  eax = socket ptr
2326
;  OUT: /
2327
;
2328
;-----------------------------------------------------------------
2329
 
2330
align 4
2331
SOCKET_is_disconnecting:
2332
 
3556 hidnplayr 2333
        DEBUGF  DEBUG_NETWORK_VERBOSE, "SOCKET_is_disconnecting: %x\n", eax
3545 hidnplayr 2334
 
3674 hidnplayr 2335
        and     [eax + SOCKET.state], not (SS_ISCONNECTING)
2336
        or      [eax + SOCKET.state], SS_ISDISCONNECTING + SS_CANTRCVMORE + SS_CANTSENDMORE
3545 hidnplayr 2337
 
2338
        jmp     SOCKET_notify
2339
 
2340
 
2341
 
2342
;-----------------------------------------------------------------
2343
;
2344
; SOCKET_is_disconnected
2345
;
2346
;  IN:  eax = socket ptr
2347
;  OUT: /
2348
;
2349
;-----------------------------------------------------------------
2350
 
2351
align 4
2352
SOCKET_is_disconnected:
2353
 
3556 hidnplayr 2354
        DEBUGF  DEBUG_NETWORK_VERBOSE, "SOCKET_is_disconnected: %x\n", eax
3545 hidnplayr 2355
 
3674 hidnplayr 2356
        and     [eax + SOCKET.state], not (SS_ISCONNECTING + SS_ISCONNECTED + SS_ISDISCONNECTING)
2357
        or      [eax + SOCKET.state], SS_CANTRCVMORE + SS_CANTSENDMORE
3545 hidnplayr 2358
 
2359
        cmp     [eax + SOCKET.Protocol], IP_PROTO_TCP
2360
        je      .tcp
2361
 
2362
        cmp     [eax + SOCKET.Protocol], IP_PROTO_UDP
2363
        je      .udp
2364
 
2365
        jmp     SOCKET_notify
2366
 
2367
  .tcp:
2368
  .udp:
2369
        mov     [eax + UDP_SOCKET.LocalPort], 0         ; UDP and TCP structs store localport at the same offset
2370
        mov     [eax + UDP_SOCKET.RemotePort], 0
2371
 
2372
        jmp     SOCKET_notify
2373
 
2374
 
2375
;-----------------------------------------------------------------
2376
;
2377
; SOCKET_cant_recv_more
2378
;
2379
;  IN:  eax = socket ptr
2380
;  OUT: /
2381
;
2382
;-----------------------------------------------------------------
2383
 
2384
align 4
2385
SOCKET_cant_recv_more:
2386
 
3556 hidnplayr 2387
        DEBUGF  DEBUG_NETWORK_VERBOSE, "SOCKET_cant_recv_more: %x\n", eax
3545 hidnplayr 2388
 
3674 hidnplayr 2389
        or      [eax + SOCKET.state], SS_CANTRCVMORE
3545 hidnplayr 2390
 
3565 hidnplayr 2391
        call    SOCKET_notify
2392
 
3545 hidnplayr 2393
        ret
2394
 
2395
 
2396
 
2397
;-----------------------------------------------------------------
2398
;
2399
; SOCKET_cant_send_more
2400
;
2401
;  IN:  eax = socket ptr
2402
;  OUT: /
2403
;
2404
;-----------------------------------------------------------------
2405
 
2406
align 4
2407
SOCKET_cant_send_more:
2408
 
3556 hidnplayr 2409
        DEBUGF  DEBUG_NETWORK_VERBOSE, "SOCKET_cant_send_more: %x\n", eax
3545 hidnplayr 2410
 
3674 hidnplayr 2411
        or      [eax + SOCKET.state], SS_CANTSENDMORE
3658 hidnplayr 2412
        mov     [eax + SOCKET.snd_proc], .notconn
3545 hidnplayr 2413
 
3565 hidnplayr 2414
        call    SOCKET_notify
2415
 
3658 hidnplayr 2416
        ret
2417
 
2418
  .notconn:
3673 hidnplayr 2419
        mov     dword[esp+20], ENOTCONN
3658 hidnplayr 2420
        mov     dword[esp+32], -1
3545 hidnplayr 2421
        ret