Subversion Repositories Kolibri OS

Rev

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

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