Subversion Repositories Kolibri OS

Rev

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

Rev Author Line No. Line
3545 hidnplayr 1
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
2
;;                                                                 ;;
7974 hidnplayr 3
;; Copyright (C) KolibriOS team 2004-2020. 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: 7974 $
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
 
335
        cmp     esi, PPP_PROTO_ETHERNET
336
        je      .pppoe
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
 
407
align 4
408
  .pppoe:
409
        push    eax
410
        init_queue (eax + SOCKET_QUEUE_LOCATION)        ; Set up data receiving queue
411
        pop     eax
412
 
6011 hidnplayr 413
        mov     [eax + SOCKET.snd_proc], socket_send_pppoe
414
        mov     [eax + SOCKET.rcv_proc], socket_receive_dgram
3545 hidnplayr 415
        ret
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
3545 hidnplayr 682
        mov     ebx, [TASK_BASE]
683
        mov     ebx, [ebx + TASKDATA.pid]
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:
6011 hidnplayr 753
        call    tcp_usrclosed
3545 hidnplayr 754
 
4366 hidnplayr 755
        test    eax, eax
756
        jz      @f
6011 hidnplayr 757
        call    tcp_output                                      ; If connection is not closed yet, send the FIN
4366 hidnplayr 758
  @@:
3545 hidnplayr 759
        ret
760
 
761
 
3658 hidnplayr 762
  .invalid:
3673 hidnplayr 763
        mov     dword[esp+20], EINVAL
3658 hidnplayr 764
        mov     dword[esp+32], -1
765
        ret
766
 
767
 
5976 hidnplayr 768
;-----------------------------------------------------------------;
769
;                                                                 ;
6011 hidnplayr 770
; socket_receive: Receive some data from the remote end.          ;
5976 hidnplayr 771
;                                                                 ;
772
;   IN: ecx = socket number                                       ;
773
;       edx = addr to application buffer                          ;
774
;       edx = length of application buffer                        ;
775
;       edi = flags                                               ;
776
;                                                                 ;
777
;  OUT: eax = number of bytes copied                              ;
778
;       eax = -1 on error                                         ;
779
;       eax = 0 when socket has been closed by the remote end     ;
780
;       ebx = errorcode on error                                  ;
781
;                                                                 ;
782
;-----------------------------------------------------------------;
3545 hidnplayr 783
align 4
6011 hidnplayr 784
socket_receive:
3545 hidnplayr 785
 
3556 hidnplayr 786
        DEBUGF  DEBUG_NETWORK_VERBOSE, "SOCKET_receive: socknum=%u bufaddr=%x buflength=%u flags=%x\n", ecx, edx, esi, edi
3545 hidnplayr 787
 
6011 hidnplayr 788
        call    socket_num_to_ptr
5969 hidnplayr 789
        test    eax, eax
3658 hidnplayr 790
        jz      .invalid
3545 hidnplayr 791
 
3704 hidnplayr 792
  .loop:
793
        push    edi
3565 hidnplayr 794
        call    [eax + SOCKET.rcv_proc]
3704 hidnplayr 795
        pop     edi
3545 hidnplayr 796
 
4219 hidnplayr 797
        test    [eax + SOCKET.state], SS_CANTRCVMORE
5364 hidnplayr 798
        jnz     .last_data
4219 hidnplayr 799
 
3704 hidnplayr 800
        cmp     ebx, EWOULDBLOCK
801
        jne     .return
802
 
803
        test    edi, MSG_DONTWAIT
804
        jnz     .return_err
805
 
5976 hidnplayr 806
        test    [eax + SOCKET.options], SO_NONBLOCK
807
        jnz     .return_err
6908 ashmew2 808
 
6011 hidnplayr 809
        call    socket_block
3704 hidnplayr 810
        jmp     .loop
811
 
812
 
813
  .invalid:
814
        push    EINVAL
815
        pop     ebx
816
  .return_err:
4219 hidnplayr 817
        mov     ecx, -1
3704 hidnplayr 818
  .return:
3673 hidnplayr 819
        mov     [esp+20], ebx
4219 hidnplayr 820
        mov     [esp+32], ecx
3565 hidnplayr 821
        ret
3545 hidnplayr 822
 
5364 hidnplayr 823
  .last_data:
824
        test    ecx, ecx
825
        jz      .return
6011 hidnplayr 826
        call    socket_notify                                   ; Call me again!
5364 hidnplayr 827
        jmp     .return
3565 hidnplayr 828
 
3658 hidnplayr 829
 
3704 hidnplayr 830
 
831
 
3545 hidnplayr 832
align 4
6011 hidnplayr 833
socket_receive_dgram:
3704 hidnplayr 834
 
3556 hidnplayr 835
        DEBUGF  DEBUG_NETWORK_VERBOSE, "SOCKET_receive: DGRAM\n"
3545 hidnplayr 836
 
5976 hidnplayr 837
        test    edi, MSG_PEEK
838
        jnz     .peek
3545 hidnplayr 839
 
5976 hidnplayr 840
        mov     ebx, esi                                        ; buffer length
841
 
3704 hidnplayr 842
        get_from_queue (eax + SOCKET_QUEUE_LOCATION), SOCKET_QUEUE_SIZE, sizeof.socket_queue_entry, .wouldblock ; sets esi only on success.
3545 hidnplayr 843
        mov     ecx, [esi + socket_queue_entry.data_size]
3556 hidnplayr 844
        DEBUGF  DEBUG_NETWORK_VERBOSE, "SOCKET_receive: %u bytes data\n", ecx
3545 hidnplayr 845
 
3704 hidnplayr 846
        cmp     ecx, ebx                                        ; If data segment does not fit in applications buffer, abort
3545 hidnplayr 847
        ja      .too_small
848
 
4219 hidnplayr 849
        push    eax ecx
3545 hidnplayr 850
        push    [esi + socket_queue_entry.buf_ptr]              ; save the buffer addr so we can clear it later
851
        mov     esi, [esi + socket_queue_entry.data_ptr]
3556 hidnplayr 852
        DEBUGF  DEBUG_NETWORK_VERBOSE, "SOCKET_receive: Source buffer=%x real addr=%x\n", [esp], esi
3545 hidnplayr 853
 
3704 hidnplayr 854
; copy the data from kernel buffer to application buffer
855
        mov     edi, edx                                        ; bufferaddr
3545 hidnplayr 856
        shr     ecx, 1
857
        jnc     .nb
858
        movsb
859
  .nb:
860
        shr     ecx, 1
861
        jnc     .nw
862
        movsw
863
  .nw:
864
        test    ecx, ecx
865
        jz      .nd
3711 clevermous 866
        rep movsd
3545 hidnplayr 867
  .nd:
868
 
6011 hidnplayr 869
        call    net_buff_free
4219 hidnplayr 870
        pop     ecx eax                                         ; return number of bytes copied to application
5976 hidnplayr 871
        cmp     [eax + SOCKET_QUEUE_LOCATION + queue.size], 0
872
        je      @f
6011 hidnplayr 873
        call    socket_notify                                   ; Queue another network event
5976 hidnplayr 874
  @@:
875
        xor     ebx, ebx                                        ; errorcode = 0 (no error)
3545 hidnplayr 876
        ret
877
 
878
  .too_small:
4219 hidnplayr 879
        mov     ecx, -1
3704 hidnplayr 880
        push    EMSGSIZE
881
        pop     ebx
3565 hidnplayr 882
        ret
3545 hidnplayr 883
 
3658 hidnplayr 884
  .wouldblock:
3704 hidnplayr 885
        push    EWOULDBLOCK
886
        pop     ebx
3658 hidnplayr 887
        ret
3545 hidnplayr 888
 
5976 hidnplayr 889
  .peek:
890
        xor     ebx, ebx
891
        xor     ecx, ecx
892
        cmp     [eax + SOCKET_QUEUE_LOCATION + queue.size], 0
893
        je      @f
894
        mov     esi, [eax + SOCKET_QUEUE_LOCATION + queue.r_ptr]
895
        mov     ecx, [esi + socket_queue_entry.data_size]
896
  @@:
897
        ret
3658 hidnplayr 898
 
7974 hidnplayr 899
align 4
900
socket_receive_tcp:
3704 hidnplayr 901
 
7974 hidnplayr 902
        call    socket_receive_stream
903
 
904
        test    ecx, ecx
905
        jz      @f
906
        push    eax ebx ecx
907
        call    tcp_output
908
        pop     ecx ebx eax
909
  @@:
910
 
911
        ret
912
 
913
 
3545 hidnplayr 914
align 4
6011 hidnplayr 915
socket_receive_local:
3545 hidnplayr 916
 
917
        ; does this socket have a PID yet?
918
        cmp     [eax + SOCKET.PID], 0
919
        jne     @f
920
 
921
        ; Change PID to that of current process
922
        mov     ebx, [TASK_BASE]
923
        mov     ebx, [ebx + TASKDATA.pid]
924
        mov     [eax + SOCKET.PID], ebx
3704 hidnplayr 925
        mov     [eax + SOCKET.TID], ebx                         ; currently TID = PID in kolibrios :(
3545 hidnplayr 926
      @@:
927
 
6011 hidnplayr 928
        mov     [eax + SOCKET.rcv_proc], socket_receive_stream
3545 hidnplayr 929
 
3704 hidnplayr 930
; ... continue to SOCKET_receive_stream
931
 
3545 hidnplayr 932
align 4
6011 hidnplayr 933
socket_receive_stream:
3545 hidnplayr 934
 
3556 hidnplayr 935
        DEBUGF  DEBUG_NETWORK_VERBOSE, "SOCKET_receive: STREAM\n"
3545 hidnplayr 936
 
7680 hidnplayr 937
        cmp     [eax + STREAM_SOCKET.rcv.size], 0
3704 hidnplayr 938
        je      .wouldblock
939
 
940
        test    edi, MSG_PEEK
941
        jnz     .peek
942
 
3545 hidnplayr 943
        mov     ecx, esi
944
        mov     edi, edx
945
        xor     edx, edx
946
 
4219 hidnplayr 947
        push    eax
3545 hidnplayr 948
        add     eax, STREAM_SOCKET.rcv
6011 hidnplayr 949
        call    socket_ring_read                                ; copy data from kernel buffer to application buffer
950
        call    socket_ring_free                                ; free read memory
4219 hidnplayr 951
        pop     eax
3545 hidnplayr 952
 
7680 hidnplayr 953
        cmp     [eax + STREAM_SOCKET.rcv.size], 0
5364 hidnplayr 954
        jne     .more_data
3704 hidnplayr 955
        xor     ebx, ebx                                        ; errorcode = 0 (no error)
3545 hidnplayr 956
        ret
957
 
5364 hidnplayr 958
  .more_data:
6011 hidnplayr 959
        call    socket_notify                                   ; Queue another network event
5364 hidnplayr 960
        xor     ebx, ebx                                        ; errorcode = 0 (no error)
961
        ret
962
 
3704 hidnplayr 963
  .wouldblock:
964
        push    EWOULDBLOCK
965
        pop     ebx
4219 hidnplayr 966
        xor     ecx, ecx
3704 hidnplayr 967
        ret
968
 
3545 hidnplayr 969
  .peek:
7680 hidnplayr 970
        mov     ecx, [eax + STREAM_SOCKET.rcv.size]
3704 hidnplayr 971
        xor     ebx, ebx
3545 hidnplayr 972
        ret
973
 
974
 
5976 hidnplayr 975
;-----------------------------------------------------------------;
976
;                                                                 ;
6011 hidnplayr 977
; socket_send: Send some data to the remote end.                  ;
5976 hidnplayr 978
;                                                                 ;
979
;   IN: ecx = socket number                                       ;
980
;       edx = pointer to data                                     ;
981
;       esi = data length                                         ;
982
;       edi = flags                                               ;
983
;                                                                 ;
984
;  OUT: eax = number of bytes sent                                ;
985
;       eax = -1 on error                                         ;
986
;       ebx = errorcode on error                                  ;
987
;                                                                 ;
988
;-----------------------------------------------------------------;
3545 hidnplayr 989
align 4
6011 hidnplayr 990
socket_send:
3545 hidnplayr 991
 
3556 hidnplayr 992
        DEBUGF  DEBUG_NETWORK_VERBOSE, "SOCKET_send: socknum=%u data ptr=%x length=%u flags=%x\n", ecx, edx, esi, edi
3545 hidnplayr 993
 
6011 hidnplayr 994
        call    socket_num_to_ptr
5969 hidnplayr 995
        test    eax, eax
3658 hidnplayr 996
        jz      .invalid
3545 hidnplayr 997
 
998
        mov     ecx, esi
999
        mov     esi, edx
1000
 
1001
        jmp     [eax + SOCKET.snd_proc]
1002
 
3658 hidnplayr 1003
  .invalid:
3673 hidnplayr 1004
        mov     dword[esp+20], EINVAL
3658 hidnplayr 1005
        mov     dword[esp+32], -1
1006
        ret
3545 hidnplayr 1007
 
3658 hidnplayr 1008
 
3545 hidnplayr 1009
align 4
6011 hidnplayr 1010
socket_send_udp:
3545 hidnplayr 1011
 
3556 hidnplayr 1012
        DEBUGF  DEBUG_NETWORK_VERBOSE, "SOCKET_send: UDP\n"
3545 hidnplayr 1013
 
1014
        mov     [esp+32], ecx
6011 hidnplayr 1015
        call    udp_output
3545 hidnplayr 1016
        cmp     eax, -1
3658 hidnplayr 1017
        je      .error
3545 hidnplayr 1018
        ret
1019
 
3658 hidnplayr 1020
  .error:
1021
        mov     dword[esp+32], -1
3673 hidnplayr 1022
        mov     dword[esp+20], EMSGSIZE ; FIXME: UDP_output should return error codes!
3658 hidnplayr 1023
        ret
3545 hidnplayr 1024
 
3658 hidnplayr 1025
 
3545 hidnplayr 1026
align 4
6011 hidnplayr 1027
socket_send_tcp:
3545 hidnplayr 1028
 
3556 hidnplayr 1029
        DEBUGF  DEBUG_NETWORK_VERBOSE, "SOCKET_send: TCP\n"
3545 hidnplayr 1030
 
1031
        push    eax
1032
        add     eax, STREAM_SOCKET.snd
6011 hidnplayr 1033
        call    socket_ring_write
3545 hidnplayr 1034
        pop     eax
1035
 
1036
        mov     [esp+32], ecx
3658 hidnplayr 1037
        mov     [eax + SOCKET.errorcode], 0
1038
        push    eax
6011 hidnplayr 1039
        call    tcp_output              ; FIXME: this doesnt look pretty, does it?
3658 hidnplayr 1040
        pop     eax
1041
        mov     eax, [eax + SOCKET.errorcode]
3673 hidnplayr 1042
        mov     [esp+20], eax
3545 hidnplayr 1043
        ret
1044
 
1045
 
1046
align 4
6011 hidnplayr 1047
socket_send_ip:
3545 hidnplayr 1048
 
3556 hidnplayr 1049
        DEBUGF  DEBUG_NETWORK_VERBOSE, "SOCKET_send: IPv4\n"
3545 hidnplayr 1050
 
1051
        mov     [esp+32], ecx
6011 hidnplayr 1052
        call    ipv4_output_raw
3545 hidnplayr 1053
        cmp     eax, -1
3658 hidnplayr 1054
        je      .error
3545 hidnplayr 1055
        ret
1056
 
3658 hidnplayr 1057
  .error:
5842 hidnplayr 1058
        mov     dword[esp+32], eax
1059
        mov     dword[esp+20], ebx
3658 hidnplayr 1060
        ret
3545 hidnplayr 1061
 
3658 hidnplayr 1062
 
3545 hidnplayr 1063
align 4
6011 hidnplayr 1064
socket_send_icmp:
3545 hidnplayr 1065
 
3556 hidnplayr 1066
        DEBUGF  DEBUG_NETWORK_VERBOSE, "SOCKET_send: ICMP\n"
3545 hidnplayr 1067
 
1068
        mov     [esp+32], ecx
6011 hidnplayr 1069
        call    icmp_output_raw
3545 hidnplayr 1070
        cmp     eax, -1
3658 hidnplayr 1071
        je      .error
3545 hidnplayr 1072
        ret
1073
 
3658 hidnplayr 1074
  .error:
5842 hidnplayr 1075
        mov     dword[esp+32], eax
1076
        mov     dword[esp+20], ebx
3658 hidnplayr 1077
        ret
3545 hidnplayr 1078
 
3658 hidnplayr 1079
 
3545 hidnplayr 1080
align 4
6011 hidnplayr 1081
socket_send_pppoe:
3545 hidnplayr 1082
 
3556 hidnplayr 1083
        DEBUGF  DEBUG_NETWORK_VERBOSE, "SOCKET_send: PPPoE\n"
3545 hidnplayr 1084
 
1085
        mov     [esp+32], ecx
1086
        mov     ebx, [eax + SOCKET.device]
1087
 
6011 hidnplayr 1088
        call    pppoe_discovery_output  ; FIXME: errorcodes
3545 hidnplayr 1089
        cmp     eax, -1
3658 hidnplayr 1090
        je      .error
3545 hidnplayr 1091
        ret
1092
 
3658 hidnplayr 1093
  .error:
1094
        mov     dword[esp+32], -1
3673 hidnplayr 1095
        mov     dword[esp+20], EMSGSIZE
3658 hidnplayr 1096
        ret
3545 hidnplayr 1097
 
1098
 
3658 hidnplayr 1099
 
3545 hidnplayr 1100
align 4
6011 hidnplayr 1101
socket_send_local:
3545 hidnplayr 1102
 
1103
        ; does this socket have a PID yet?
1104
        cmp     [eax + SOCKET.PID], 0
1105
        jne     @f
1106
 
1107
        ; Change PID to that of current process
1108
        mov     ebx, [TASK_BASE]
1109
        mov     ebx, [ebx + TASKDATA.pid]
1110
        mov     [eax + SOCKET.PID], ebx
1111
        mov     [eax + SOCKET.TID], ebx         ; currently TID = PID in kolibrios :(
1112
      @@:
6011 hidnplayr 1113
        mov     [eax + SOCKET.snd_proc], socket_send_local_initialized
3545 hidnplayr 1114
 
1115
align 4
6011 hidnplayr 1116
socket_send_local_initialized:
3545 hidnplayr 1117
 
3556 hidnplayr 1118
        DEBUGF  DEBUG_NETWORK_VERBOSE, "SOCKET_send: LOCAL\n"
3545 hidnplayr 1119
 
1120
        ; get the other side's socket and check if it still exists
1121
        mov     eax, [eax + SOCKET.device]
6011 hidnplayr 1122
        call    socket_check
3658 hidnplayr 1123
        jz      .invalid
3545 hidnplayr 1124
 
1125
        ; allright, shove in the data!
1126
        push    eax
1127
        add     eax, STREAM_SOCKET.rcv
6011 hidnplayr 1128
        call    socket_ring_write
3545 hidnplayr 1129
        pop     eax
1130
 
1131
        ; return the number of written bytes (or errorcode) to application
1132
        mov     [esp+32], ecx
1133
 
1134
        ; and notify the other end
6011 hidnplayr 1135
        call    socket_notify
3545 hidnplayr 1136
 
1137
        ret
1138
 
3658 hidnplayr 1139
  .invalid:
1140
        mov     dword[esp+32], -1
3673 hidnplayr 1141
        mov     dword[esp+20], EINVAL
3658 hidnplayr 1142
        ret
3545 hidnplayr 1143
 
3658 hidnplayr 1144
 
5976 hidnplayr 1145
;-----------------------------------------------------------------;
1146
;                                                                 ;
6011 hidnplayr 1147
; socket_get_opt: Read a socket option                            ;
5976 hidnplayr 1148
;                                                                 ;
1149
;   IN: ecx = socket number                                       ;
1150
;       edx = pointer to socket options struct                    ;
1151
;                                                                 ;
1152
;  OUT: eax = 0 on success                                        ;
1153
;       eax = -1 on error                                         ;
1154
;       ebx = errorcode on error                                  ;
1155
;                                                                 ;
1156
;-----------------------------------------------------------------;
1157
align 4
6011 hidnplayr 1158
socket_get_opt:
5976 hidnplayr 1159
 
1160
; FIXME:
3545 hidnplayr 1161
; At moment, uses only pseudo-optname -2 for get last_ack_number for TCP.
1162
; TODO: find best way to notify that send()'ed data were acknowledged
1163
; Also pseudo-optname -3 is valid and returns socket state, one of TCPS_*.
1164
 
3556 hidnplayr 1165
        DEBUGF  DEBUG_NETWORK_VERBOSE, "SOCKET_get_opt\n"
3545 hidnplayr 1166
 
6011 hidnplayr 1167
        call    socket_num_to_ptr
5969 hidnplayr 1168
        test    eax, eax
3658 hidnplayr 1169
        jz      .invalid
3545 hidnplayr 1170
 
1171
        cmp     dword [edx], IP_PROTO_TCP
3658 hidnplayr 1172
        jne     .invalid
3545 hidnplayr 1173
        cmp     dword [edx+4], -2
1174
        je      @f
1175
        cmp     dword [edx+4], -3
3658 hidnplayr 1176
        jne     .invalid
3545 hidnplayr 1177
@@:
1178
;        mov     eax, [edx+12]
1179
;        test    eax, eax
1180
;        jz      .fail
1181
;        cmp     dword [eax], 4
1182
;        mov     dword [eax], 4
1183
;        jb      .fail
1184
;        stdcall net_socket_num_to_addr, ecx
1185
;        test    eax, eax
1186
;        jz      .fail
1187
;        ; todo: check that eax is really TCP socket
1188
;        mov     ecx, [eax + TCP_SOCKET.last_ack_number]
1189
;        cmp     dword [edx+4], -2
1190
;        jz      @f
1191
;        mov     ecx, [eax + TCP_SOCKET.state]
1192
@@:
1193
        mov     eax, [edx+8]
1194
        test    eax, eax
1195
        jz      @f
1196
        mov     [eax], ecx
1197
@@:
1198
        mov     dword [esp+32], 0
1199
        ret
1200
 
3658 hidnplayr 1201
  .invalid:
1202
        mov     dword[esp+32], -1
3673 hidnplayr 1203
        mov     dword[esp+20], EINVAL
3658 hidnplayr 1204
        ret
3545 hidnplayr 1205
 
1206
 
5976 hidnplayr 1207
;-----------------------------------------------------------------;
1208
;                                                                 ;
6011 hidnplayr 1209
; socket_set_options: Set a socket option.                        ;
5976 hidnplayr 1210
;                                                                 ;
1211
;   IN: ecx = socket number                                       ;
1212
;       edx = pointer to socket options struct                    ;
1213
;                                                                 ;
1214
;  OUT: eax = 0 on success                                        ;
1215
;       eax = -1 on error                                         ;
1216
;       ebx = errorcode on error                                  ;
1217
;                                                                 ;
1218
;-----------------------------------------------------------------;
3545 hidnplayr 1219
align 4
6011 hidnplayr 1220
socket_set_opt:
3545 hidnplayr 1221
 
3556 hidnplayr 1222
        DEBUGF  DEBUG_NETWORK_VERBOSE, "SOCKET_set_opt\n"
3545 hidnplayr 1223
 
6011 hidnplayr 1224
        call    socket_num_to_ptr
5969 hidnplayr 1225
        test    eax, eax
3658 hidnplayr 1226
        jz      .invalid
3545 hidnplayr 1227
 
5842 hidnplayr 1228
        cmp     [edx + socket_options.level], IP_PROTO_IP
1229
        je      .ip
1230
        cmp     [edx + socket_options.level], SOL_SOCKET
3658 hidnplayr 1231
        jne     .invalid
3545 hidnplayr 1232
 
5842 hidnplayr 1233
  .socket:
1234
        cmp     [edx + socket_options.optname], SO_BINDTODEVICE
1235
        jne     .invalid
3545 hidnplayr 1236
 
1237
  .bind:
5842 hidnplayr 1238
        cmp     [edx + socket_options.optlen], 0
3545 hidnplayr 1239
        je      .unbind
1240
 
5842 hidnplayr 1241
        movzx   edx, byte[edx + socket_options.optval]
3600 hidnplayr 1242
        cmp     edx, NET_DEVICES_MAX
3658 hidnplayr 1243
        ja      .invalid
3545 hidnplayr 1244
 
7679 hidnplayr 1245
        mov     edx, [net_device_list + 4*edx]
3545 hidnplayr 1246
        test    edx, edx
3658 hidnplayr 1247
        jz      .already
3545 hidnplayr 1248
        mov     [eax + SOCKET.device], edx
1249
 
5584 hidnplayr 1250
        DEBUGF  DEBUG_NETWORK_VERBOSE, "SOCKET_set_opt: Bound socket %x to device %x\n", eax, edx
3545 hidnplayr 1251
 
3658 hidnplayr 1252
        mov     dword[esp+32], 0        ; success!
3545 hidnplayr 1253
        ret
1254
 
1255
  .unbind:
1256
        mov     [eax + SOCKET.device], 0
1257
 
3658 hidnplayr 1258
        mov     dword[esp+32], 0        ; success!
3545 hidnplayr 1259
        ret
1260
 
5842 hidnplayr 1261
  .ip:
1262
        cmp     [edx + socket_options.optname], IP_TTL
1263
        jne     .invalid
1264
 
1265
  .ttl:
1266
        mov     bl, byte[edx + socket_options.optval]
1267
        mov     [eax + IP_SOCKET.ttl], bl
1268
 
1269
        mov     dword[esp+32], 0        ; success!
1270
        ret
1271
 
3658 hidnplayr 1272
  .already:
3673 hidnplayr 1273
        mov     dword[esp+20], EALREADY
3658 hidnplayr 1274
        mov     dword[esp+32], -1
1275
        ret
3545 hidnplayr 1276
 
5842 hidnplayr 1277
  .invalid:
1278
        mov     dword[esp+20], EINVAL
1279
        mov     dword[esp+32], -1
1280
        ret
3545 hidnplayr 1281
 
3658 hidnplayr 1282
 
1283
 
5842 hidnplayr 1284
 
5976 hidnplayr 1285
;-----------------------------------------------------------------;
1286
;                                                                 ;
6011 hidnplayr 1287
; socket_pair: Allocate a pair of linked local sockets.           ;
5976 hidnplayr 1288
;                                                                 ;
1289
;  IN: /                                                          ;
1290
;                                                                 ;
1291
; OUT: eax = socket1 num on success                               ;
1292
;      eax = -1 on error                                          ;
1293
;      ebx = socket2 num on success                               ;
1294
;      ebx = errorcode on error                                   ;
1295
;                                                                 ;
1296
;-----------------------------------------------------------------;
3545 hidnplayr 1297
align 4
6011 hidnplayr 1298
socket_pair:
3545 hidnplayr 1299
 
3556 hidnplayr 1300
        DEBUGF  DEBUG_NETWORK_VERBOSE, "SOCKET_pair\n"
3545 hidnplayr 1301
 
6011 hidnplayr 1302
        call    socket_alloc
4535 hidnplayr 1303
        test    eax, eax
3658 hidnplayr 1304
        jz      .nomem1
3545 hidnplayr 1305
        mov     [esp+32], edi   ; application's eax
1306
 
1307
        mov     [eax + SOCKET.Domain], AF_LOCAL
1308
        mov     [eax + SOCKET.Type], SOCK_STREAM
1309
        mov     [eax + SOCKET.Protocol], 0              ;;; CHECKME
6011 hidnplayr 1310
        mov     [eax + SOCKET.snd_proc], socket_send_local
1311
        mov     [eax + SOCKET.rcv_proc], socket_receive_local
3545 hidnplayr 1312
        mov     [eax + SOCKET.PID], 0
1313
        mov     ebx, eax
1314
 
6011 hidnplayr 1315
        call    socket_alloc
4535 hidnplayr 1316
        test    eax, eax
3658 hidnplayr 1317
        jz      .nomem2
3673 hidnplayr 1318
        mov     [esp+20], edi   ; application's ebx
3545 hidnplayr 1319
 
1320
        mov     [eax + SOCKET.Domain], AF_LOCAL
1321
        mov     [eax + SOCKET.Type], SOCK_STREAM
1322
        mov     [eax + SOCKET.Protocol], 0              ;;; CHECKME
6011 hidnplayr 1323
        mov     [eax + SOCKET.snd_proc], socket_send_local
1324
        mov     [eax + SOCKET.rcv_proc], socket_receive_local
3545 hidnplayr 1325
        mov     [eax + SOCKET.PID], 0
1326
 
1327
        ; Link the two sockets to eachother
1328
        mov     [eax + SOCKET.device], ebx
1329
        mov     [ebx + SOCKET.device], eax
1330
 
1331
        lea     eax, [eax + STREAM_SOCKET.rcv]
6011 hidnplayr 1332
        call    socket_ring_create
5155 hidnplayr 1333
        test    eax, eax
5969 hidnplayr 1334
        jz      .nomem2
3545 hidnplayr 1335
 
1336
        lea     eax, [ebx + STREAM_SOCKET.rcv]
6011 hidnplayr 1337
        call    socket_ring_create
5155 hidnplayr 1338
        test    eax, eax
1339
        jz      .nomem2
3545 hidnplayr 1340
 
1341
        ret
1342
 
3658 hidnplayr 1343
  .nomem2:
5969 hidnplayr 1344
        mov     eax, [esp+20]
6011 hidnplayr 1345
        call    socket_free
5969 hidnplayr 1346
 
3658 hidnplayr 1347
  .nomem1:
5969 hidnplayr 1348
        mov     eax, [esp+32]
6011 hidnplayr 1349
        call    socket_free
5969 hidnplayr 1350
 
3658 hidnplayr 1351
        mov     dword[esp+32], -1
5969 hidnplayr 1352
        mov     dword[esp+20], ENOMEM
3658 hidnplayr 1353
        ret
3545 hidnplayr 1354
 
1355
 
1356
 
5976 hidnplayr 1357
;-----------------------------------------------------------------;
1358
;                                                                 ;
6011 hidnplayr 1359
; socket_debug: Copy socket variables to application buffer.      ;
5976 hidnplayr 1360
;                                                                 ;
1361
;   IN: ecx = socket number                                       ;
1362
;       edx = pointer to application buffer                       ;
1363
;                                                                 ;
1364
;  OUT: eax = 0 on success                                        ;
1365
;       eax = -1 on error                                         ;
1366
;       ebx = errorcode on error                                  ;
1367
;                                                                 ;
1368
;-----------------------------------------------------------------;
3545 hidnplayr 1369
align 4
6011 hidnplayr 1370
socket_debug:
3545 hidnplayr 1371
 
3556 hidnplayr 1372
        DEBUGF  DEBUG_NETWORK_VERBOSE, "SOCKET_debug\n"
3545 hidnplayr 1373
 
1374
        mov     edi, edx
1375
 
1376
        test    ecx, ecx
1377
        jz      .returnall
1378
 
6011 hidnplayr 1379
        call    socket_num_to_ptr
5969 hidnplayr 1380
        test    eax, eax
3658 hidnplayr 1381
        jz      .invalid
3545 hidnplayr 1382
 
1383
        mov     esi, eax
6413 hidnplayr 1384
        mov     ecx, SOCKET_STRUCT_SIZE/4
3711 clevermous 1385
        rep movsd
3545 hidnplayr 1386
 
3658 hidnplayr 1387
        mov     dword[esp+32], 0
3545 hidnplayr 1388
        ret
1389
 
1390
  .returnall:
1391
        mov     ebx, net_sockets
1392
  .next_socket:
1393
        mov     ebx, [ebx + SOCKET.NextPtr]
1394
        test    ebx, ebx
1395
        jz      .done
1396
        mov     eax, [ebx + SOCKET.Number]
1397
        stosd
1398
        jmp     .next_socket
1399
  .done:
1400
        xor     eax, eax
1401
        stosd
3658 hidnplayr 1402
        mov     dword[esp+32], eax
1403
        ret
3545 hidnplayr 1404
 
3658 hidnplayr 1405
  .invalid:
1406
        mov     dword[esp+32], -1
5969 hidnplayr 1407
        mov     dword[esp+20], EINVAL
3545 hidnplayr 1408
        ret
1409
 
1410
 
5976 hidnplayr 1411
;-----------------------------------------------------------------;
1412
;   ____                                                 ____     ;
1413
;   \  /              End of sockets API                 \  /     ;
1414
;    \/                                                   \/      ;
1415
;    ()        Internally used functions follow           ()      ;
1416
;                                                                 ;
1417
;-----------------------------------------------------------------;
1418
 
1419
 
1420
;-----------------------------------------------------------------;
1421
;                                                                 ;
6011 hidnplayr 1422
; socket_find_port:                                               ;
5976 hidnplayr 1423
; Fill in the local port number for TCP and UDP sockets           ;
1424
; This procedure always works because the number of sockets is    ;
1425
; limited to a smaller number then the number of possible ports   ;
1426
;                                                                 ;
1427
;  IN:  eax = socket pointer                                      ;
1428
;                                                                 ;
1429
;  OUT: /                                                         ;
1430
;                                                                 ;
1431
;-----------------------------------------------------------------;
3545 hidnplayr 1432
align 4
6011 hidnplayr 1433
socket_find_port:
3545 hidnplayr 1434
 
3556 hidnplayr 1435
        DEBUGF  DEBUG_NETWORK_VERBOSE, "SOCKET_find_port\n"
3545 hidnplayr 1436
 
1437
        push    ebx esi ecx
1438
 
1439
        cmp     [eax + SOCKET.Protocol], IP_PROTO_UDP
1440
        je      .udp
1441
 
1442
        cmp     [eax + SOCKET.Protocol], IP_PROTO_TCP
1443
        je      .tcp
1444
 
1445
        pop     ecx esi ebx
1446
        ret
1447
 
1448
  .udp:
1449
        mov     bx, [last_UDP_port]
1450
        call    .findit
1451
        mov     [last_UDP_port], bx
1452
 
1453
        pop     ecx esi ebx
1454
        ret
1455
 
1456
  .tcp:
1457
        mov     bx, [last_TCP_port]
1458
        call    .findit
1459
        mov     [last_TCP_port], bx
1460
 
1461
        pop     ecx esi ebx
1462
        ret
1463
 
1464
 
1465
  .restart:
1466
        mov     bx, MIN_EPHEMERAL_PORT_N
1467
  .findit:
1468
        cmp     bx, MAX_EPHEMERAL_PORT_N
1469
        je      .restart
1470
 
1471
        add     bh, 1
1472
        adc     bl, 0
1473
 
6011 hidnplayr 1474
        call    socket_check_port
3545 hidnplayr 1475
        jz      .findit
1476
        ret
1477
 
1478
 
1479
 
5976 hidnplayr 1480
;-----------------------------------------------------------------;
1481
;                                                                 ;
6011 hidnplayr 1482
; socket_check_port: (to be used with AF_INET only!)              ;
5976 hidnplayr 1483
; Checks if a local port number is unused                         ;
1484
; If the proposed port number is unused, it is filled in in the   ;
6011 hidnplayr 1485
; socket structure.                                               ;
5976 hidnplayr 1486
;                                                                 ;
1487
;   IN: eax = socket ptr                                          ;
1488
;       bx = proposed socket number (network byte order)          ;
1489
;                                                                 ;
1490
;  OUT: ZF = set on error                                         ;
1491
;                                                                 ;
1492
;-----------------------------------------------------------------;
3545 hidnplayr 1493
align 4
6011 hidnplayr 1494
socket_check_port:
3545 hidnplayr 1495
 
3556 hidnplayr 1496
        DEBUGF  DEBUG_NETWORK_VERBOSE, "SOCKET_check_port: "
3545 hidnplayr 1497
 
3647 hidnplayr 1498
        pusha
1499
        mov     ecx, socket_mutex
1500
        call    mutex_lock
1501
        popa
1502
 
3545 hidnplayr 1503
        mov     ecx, [eax + SOCKET.Protocol]
1504
        mov     edx, [eax + IP_SOCKET.LocalIP]
1505
        mov     esi, net_sockets
1506
 
1507
  .next_socket:
1508
        mov     esi, [esi + SOCKET.NextPtr]
1509
        or      esi, esi
1510
        jz      .port_ok
1511
 
1512
        cmp     [esi + SOCKET.Protocol], ecx
1513
        jne     .next_socket
1514
 
1515
        cmp     [esi + IP_SOCKET.LocalIP], edx
1516
        jne     .next_socket
1517
 
1518
        cmp     [esi + UDP_SOCKET.LocalPort], bx
1519
        jne     .next_socket
1520
 
3647 hidnplayr 1521
        pusha
1522
        mov     ecx, socket_mutex
1523
        call    mutex_unlock
1524
        popa
1525
 
3556 hidnplayr 1526
        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 1527
        ret
1528
 
1529
  .port_ok:
3647 hidnplayr 1530
        pusha
1531
        mov     ecx, socket_mutex
1532
        call    mutex_unlock
1533
        popa
1534
 
3556 hidnplayr 1535
        DEBUGF  DEBUG_NETWORK_VERBOSE, "local port %x is free\n", bx         ; FIXME: find a way to print big endian values with debugf
3545 hidnplayr 1536
        mov     [eax + UDP_SOCKET.LocalPort], bx
1537
        or      bx, bx                                  ; clear the zero-flag
1538
        ret
1539
 
1540
 
1541
 
5976 hidnplayr 1542
;-----------------------------------------------------------------;
1543
;                                                                 ;
6011 hidnplayr 1544
; socket_input: Update a (stateless) socket with received data.   ;
5976 hidnplayr 1545
;                                                                 ;
1546
; Note: The socket's mutex should already be set !                ;
1547
;                                                                 ;
1548
;   IN: eax = socket ptr                                          ;
1549
;       ecx = data size                                           ;
1550
;       esi = ptr to data                                         ;
1551
;       [esp] = ptr to buf                                        ;
1552
;                                                                 ;
1553
;  OUT: /                                                         ;
1554
;                                                                 ;
1555
;-----------------------------------------------------------------;
3545 hidnplayr 1556
align 4
6011 hidnplayr 1557
socket_input:
3545 hidnplayr 1558
 
3556 hidnplayr 1559
        DEBUGF  DEBUG_NETWORK_VERBOSE, "SOCKET_input: socket=%x, data=%x size=%u\n", eax, esi, ecx
3545 hidnplayr 1560
 
5522 hidnplayr 1561
        push    ecx
3545 hidnplayr 1562
        push    esi
1563
        mov     esi, esp
1564
 
6011 hidnplayr 1565
        add_to_queue (eax + SOCKET_QUEUE_LOCATION), SOCKET_QUEUE_SIZE, sizeof.socket_queue_entry, .full
3545 hidnplayr 1566
 
3556 hidnplayr 1567
        DEBUGF  DEBUG_NETWORK_VERBOSE, "SOCKET_input: success\n"
3545 hidnplayr 1568
        add     esp, sizeof.socket_queue_entry
1569
 
1570
        pusha
1571
        lea     ecx, [eax + SOCKET.mutex]
1572
        call    mutex_unlock
1573
        popa
1574
 
6011 hidnplayr 1575
        jmp     socket_notify
3545 hidnplayr 1576
 
1577
  .full:
7680 hidnplayr 1578
        DEBUGF  DEBUG_NETWORK_ERROR, "SOCKET_input: socket %x is full!\n", eax
3545 hidnplayr 1579
 
1580
        pusha
1581
        lea     ecx, [eax + SOCKET.mutex]
1582
        call    mutex_unlock
1583
        popa
1584
 
5842 hidnplayr 1585
        add     esp, 8
6011 hidnplayr 1586
        call    net_buff_free
3545 hidnplayr 1587
        ret
1588
 
1589
 
5976 hidnplayr 1590
;-----------------------------------------------------------------;
1591
;                                                                 ;
6011 hidnplayr 1592
; socket_ring_create: Create a ringbuffer for sockets.            ;
5976 hidnplayr 1593
;                                                                 ;
1594
;   IN: eax = ptr to ring struct                                  ;
1595
;                                                                 ;
1596
;  OUT: eax = 0 on error                                          ;
1597
;       eax = start ptr                                           ;
1598
;                                                                 ;
1599
;-----------------------------------------------------------------;
3545 hidnplayr 1600
align 4
6011 hidnplayr 1601
socket_ring_create:
3545 hidnplayr 1602
 
1603
        push    esi
1604
        mov     esi, eax
1605
 
1606
        push    edx
6413 hidnplayr 1607
        stdcall create_ring_buffer, SOCKET_BUFFER_SIZE, PG_SWR
3545 hidnplayr 1608
        pop     edx
5155 hidnplayr 1609
        test    eax, eax
1610
        jz      .fail
3545 hidnplayr 1611
 
5969 hidnplayr 1612
        DEBUGF  DEBUG_NETWORK_VERBOSE, "SOCKET_ring_create: %x\n", eax
3545 hidnplayr 1613
 
1614
        pusha
1615
        lea     ecx, [esi + RING_BUFFER.mutex]
1616
        call    mutex_init
1617
        popa
1618
 
1619
        mov     [esi + RING_BUFFER.start_ptr], eax
1620
        mov     [esi + RING_BUFFER.write_ptr], eax
1621
        mov     [esi + RING_BUFFER.read_ptr], eax
1622
        mov     [esi + RING_BUFFER.size], 0
6413 hidnplayr 1623
        add     eax, SOCKET_BUFFER_SIZE
3545 hidnplayr 1624
        mov     [esi + RING_BUFFER.end_ptr], eax
1625
        mov     eax, esi
1626
 
5969 hidnplayr 1627
        pop     esi
1628
        ret
1629
 
5155 hidnplayr 1630
  .fail:
5969 hidnplayr 1631
        DEBUGF  DEBUG_NETWORK_ERROR, "SOCKET_ring_create: Out of memory!\n"
5566 hidnplayr 1632
        pop     esi
3545 hidnplayr 1633
        ret
1634
 
5976 hidnplayr 1635
;-----------------------------------------------------------------;
1636
;                                                                 ;
6011 hidnplayr 1637
; socket_ring_write: Write data to ring buffer.                   ;
5976 hidnplayr 1638
;                                                                 ;
1639
;   IN: eax = ptr to ring struct                                  ;
1640
;       ecx = data size                                           ;
1641
;       esi = ptr to data                                         ;
1642
;                                                                 ;
1643
;  OUT: ecx = number of bytes stored                              ;
1644
;                                                                 ;
1645
;-----------------------------------------------------------------;
3545 hidnplayr 1646
align 4
6011 hidnplayr 1647
socket_ring_write:
3545 hidnplayr 1648
 
3556 hidnplayr 1649
        DEBUGF  DEBUG_NETWORK_VERBOSE, "SOCKET_ring_write: ringbuff=%x ptr=%x size=%u\n", eax, esi, ecx
3545 hidnplayr 1650
 
1651
; lock mutex
1652
        pusha
1653
        lea     ecx, [eax + RING_BUFFER.mutex]
1654
        call    mutex_lock                                      ; TODO: check what registers this function actually destroys
1655
        popa
1656
 
1657
; calculate available size
6413 hidnplayr 1658
        mov     edi, SOCKET_BUFFER_SIZE
3545 hidnplayr 1659
        sub     edi, [eax + RING_BUFFER.size]                   ; available buffer size in edi
1660
        cmp     ecx, edi
1661
        jbe     .copy
1662
        mov     ecx, edi
1663
  .copy:
1664
        mov     edi, [eax + RING_BUFFER.write_ptr]
3556 hidnplayr 1665
        DEBUGF  DEBUG_NETWORK_VERBOSE, "SOCKET_ring_write: %u bytes from %x to %x\n", ecx, esi, edi
3545 hidnplayr 1666
 
1667
; update write ptr
1668
        push    edi
1669
        add     edi, ecx
1670
        cmp     edi, [eax + RING_BUFFER.end_ptr]
1671
        jb      @f
6413 hidnplayr 1672
        sub     edi, SOCKET_BUFFER_SIZE                         ; WRAP
3545 hidnplayr 1673
  @@:
1674
        mov     [eax + RING_BUFFER.write_ptr], edi
1675
        pop     edi
1676
 
1677
; update size
1678
        add     [eax + RING_BUFFER.size], ecx
1679
 
1680
; copy the data
1681
        push    ecx
1682
        shr     ecx, 1
1683
        jnc     .nb
1684
        movsb
1685
  .nb:
1686
        shr     ecx, 1
1687
        jnc     .nw
1688
        movsw
1689
  .nw:
1690
        test    ecx, ecx
1691
        jz      .nd
3711 clevermous 1692
        rep movsd
3545 hidnplayr 1693
  .nd:
1694
        pop     ecx
1695
 
1696
; unlock mutex
4344 hidnplayr 1697
        pusha
3545 hidnplayr 1698
        lea     ecx, [eax + RING_BUFFER.mutex]
1699
        call    mutex_unlock                                    ; TODO: check what registers this function actually destroys
4344 hidnplayr 1700
        popa
3545 hidnplayr 1701
 
1702
        ret
1703
 
5976 hidnplayr 1704
;-----------------------------------------------------------------;
1705
;                                                                 ;
6011 hidnplayr 1706
; socket_ring_read: Read from ring buffer                         ;
5976 hidnplayr 1707
;                                                                 ;
1708
;   IN: eax = ring struct ptr                                     ;
1709
;       ecx = bytes to read                                       ;
1710
;       edx = offset                                              ;
1711
;       edi = ptr to buffer start                                 ;
1712
;                                                                 ;
1713
;  OUT: eax = unchanged                                           ;
1714
;       ecx = number of bytes read (0 on error)                   ;
1715
;       edx = destroyed                                           ;
1716
;       esi = destroyed                                           ;
1717
;       edi = ptr to buffer end                                   ;
1718
;                                                                 ;
1719
;-----------------------------------------------------------------;
3545 hidnplayr 1720
align 4
6011 hidnplayr 1721
socket_ring_read:
3545 hidnplayr 1722
 
3556 hidnplayr 1723
        DEBUGF  DEBUG_NETWORK_VERBOSE, "SOCKET_ring_read: ringbuff=%x ptr=%x size=%u offset=%x\n", eax, edi, ecx, edx
3545 hidnplayr 1724
 
1725
        pusha
1726
        lea     ecx, [eax + RING_BUFFER.mutex]
1727
        call    mutex_lock                                      ; TODO: check what registers this function actually destroys
1728
        popa
1729
 
1730
        mov     esi, [eax + RING_BUFFER.read_ptr]
1731
        add     esi, edx                                        ; esi = start_ptr + offset
1732
 
1733
        neg     edx
1734
        add     edx, [eax + RING_BUFFER.size]                   ; edx = snd.size - offset
1735
        jle     .no_data_at_all
1736
 
1737
        pusha
1738
        lea     ecx, [eax + RING_BUFFER.mutex]
1739
        call    mutex_unlock                                    ; TODO: check what registers this function actually destroys
1740
        popa
1741
 
1742
        cmp     ecx, edx
1743
        ja      .less_data
1744
 
1745
  .copy:
3556 hidnplayr 1746
        DEBUGF  DEBUG_NETWORK_VERBOSE, "SOCKET_ring_read: %u bytes from %x to %x\n", ecx, esi, edi
3545 hidnplayr 1747
        push    ecx
1748
        shr     ecx, 1
1749
        jnc     .nb
1750
        movsb
1751
  .nb:
1752
        shr     ecx, 1
1753
        jnc     .nw
1754
        movsw
1755
  .nw:
1756
        test    ecx, ecx
1757
        jz      .nd
3711 clevermous 1758
        rep movsd
3545 hidnplayr 1759
  .nd:
1760
        pop     ecx
1761
        ret
1762
 
1763
  .no_data_at_all:
1764
        pusha
1765
        lea     ecx, [eax + RING_BUFFER.mutex]
1766
        call    mutex_unlock                                    ; TODO: check what registers this function actually destroys
1767
        popa
1768
 
7680 hidnplayr 1769
        DEBUGF  DEBUG_NETWORK_ERROR, "SOCKET_ring_read: no data at all!\n"
3545 hidnplayr 1770
        xor     ecx, ecx
1771
        ret
1772
 
1773
  .less_data:
1774
        mov     ecx, edx
1775
        jmp     .copy
1776
 
1777
 
5976 hidnplayr 1778
;-----------------------------------------------------------------;
1779
;                                                                 ;
6011 hidnplayr 1780
; socket_ring_free: Free data from a ringbuffer.                  ;
5976 hidnplayr 1781
;                                                                 ;
1782
;   IN: eax = ptr to ring struct                                  ;
1783
;       ecx = data size                                           ;
1784
;                                                                 ;
1785
;  OUT: ecx = number of freed bytes                               ;
1786
;                                                                 ;
1787
;-----------------------------------------------------------------;
3545 hidnplayr 1788
align 4
6011 hidnplayr 1789
socket_ring_free:
3545 hidnplayr 1790
 
3556 hidnplayr 1791
        DEBUGF  DEBUG_NETWORK_VERBOSE, "SOCKET_ring_free: %u bytes from ring %x\n", ecx, eax
3545 hidnplayr 1792
 
1793
        push    eax ecx
1794
        lea     ecx, [eax + RING_BUFFER.mutex]
1795
        call    mutex_lock                                      ; TODO: check what registers this function actually destroys
1796
        pop     ecx eax
1797
 
1798
        sub     [eax + RING_BUFFER.size], ecx
1799
        jb      .error
1800
        add     [eax + RING_BUFFER.read_ptr], ecx
1801
 
1802
        mov     edx, [eax + RING_BUFFER.end_ptr]
1803
        cmp     [eax + RING_BUFFER.read_ptr], edx
1804
        jb      @f
6413 hidnplayr 1805
        sub     [eax + RING_BUFFER.read_ptr], SOCKET_BUFFER_SIZE
3545 hidnplayr 1806
       @@:
1807
 
1808
        push    eax ecx
1809
        lea     ecx, [eax + RING_BUFFER.mutex]                  ; TODO: check what registers this function actually destroys
1810
        call    mutex_unlock
1811
        pop     ecx eax
1812
 
1813
        ret
1814
 
1815
  .error:       ; we could free all available bytes, but that would be stupid, i guess..
7680 hidnplayr 1816
        DEBUGF  DEBUG_NETWORK_ERROR, "SOCKET_ring_free: buffer=%x error!\n", eax
3545 hidnplayr 1817
        add     [eax + RING_BUFFER.size], ecx
1818
 
1819
        push    eax
1820
        lea     ecx, [eax + RING_BUFFER.mutex]
1821
        call    mutex_unlock                                    ; TODO: check what registers this function actually destroys
1822
        pop     eax
1823
 
1824
        xor     ecx, ecx
1825
        ret
1826
 
1827
 
5976 hidnplayr 1828
;-----------------------------------------------------------------;
1829
;                                                                 ;
6011 hidnplayr 1830
; socket_block: Suspend the thread attached to a socket.          ;
5976 hidnplayr 1831
;                                                                 ;
1832
;   IN: eax = socket ptr                                          ;
1833
;                                                                 ;
1834
;  OUT: eax = unchanged                                           ;
1835
;                                                                 ;
1836
;-----------------------------------------------------------------;
3545 hidnplayr 1837
align 4
6011 hidnplayr 1838
socket_block:
3545 hidnplayr 1839
 
6908 ashmew2 1840
        DEBUGF  DEBUG_NETWORK_VERBOSE, "SOCKET_block: %x\n", eax
3545 hidnplayr 1841
 
4520 hidnplayr 1842
        push    eax
1843
 
3545 hidnplayr 1844
        pushf
1845
        cli
1846
        ; Set the 'socket is blocked' flag
1847
        or      [eax + SOCKET.state], SS_BLOCKED
1848
 
1849
        ; Suspend the thread
1850
        push    edx
1851
        mov     edx, [TASK_BASE]
7974 hidnplayr 1852
        mov     [edx + TASKDATA.state], TSTATE_RUN_SUSPENDED
3545 hidnplayr 1853
 
1854
        ; Remember the thread ID so we can wake it up again
1855
        mov     edx, [edx + TASKDATA.pid]
3556 hidnplayr 1856
        DEBUGF  DEBUG_NETWORK_VERBOSE, "SOCKET_block: suspending thread: %u\n", edx
3545 hidnplayr 1857
        mov     [eax + SOCKET.TID], edx
1858
        pop     edx
4520 hidnplayr 1859
        popf
3545 hidnplayr 1860
 
1861
        call    change_task
3674 hidnplayr 1862
        pop     eax
3545 hidnplayr 1863
 
6908 ashmew2 1864
        DEBUGF  DEBUG_NETWORK_VERBOSE, "SOCKET_block: continuing\n"
3545 hidnplayr 1865
 
1866
        ret
1867
 
1868
 
5976 hidnplayr 1869
;-----------------------------------------------------------------;
1870
;                                                                 ;
6011 hidnplayr 1871
; socket_notify: Wake up socket owner thread.                     ;
5976 hidnplayr 1872
;                                                                 ;
1873
;   IN: eax = socket ptr                                          ;
1874
;                                                                 ;
1875
;  OUT: eax = unchanged                                           ;
1876
;                                                                 ;
1877
;-----------------------------------------------------------------;
3545 hidnplayr 1878
align 4
6011 hidnplayr 1879
socket_notify:
3545 hidnplayr 1880
 
3556 hidnplayr 1881
        DEBUGF  DEBUG_NETWORK_VERBOSE, "SOCKET_notify: %x\n", eax
3545 hidnplayr 1882
 
6011 hidnplayr 1883
        call    socket_check
3545 hidnplayr 1884
        jz      .error
1885
 
4527 hidnplayr 1886
; Find the associated thread's TASK_DATA
1887
        push    ebx ecx esi
1888
        mov     ebx, [eax + SOCKET.TID]
1889
        test    ebx, ebx
1890
        jz      .error2
1891
        xor     ecx, ecx
3545 hidnplayr 1892
        inc     ecx
4527 hidnplayr 1893
        mov     esi, TASK_DATA
1894
  .next:
1895
        cmp     [esi + TASKDATA.pid], ebx
1896
        je      .found
1897
        inc     ecx
7974 hidnplayr 1898
        add     esi, sizeof.TASKDATA
3545 hidnplayr 1899
        cmp     ecx, [TASK_COUNT]
4527 hidnplayr 1900
        jbe     .next
1901
 
1902
  .error2:
3545 hidnplayr 1903
; PID not found, TODO: close socket!
4527 hidnplayr 1904
        DEBUGF  DEBUG_NETWORK_ERROR, "SOCKET_notify: error finding thread 0x%x !\n", ebx
1905
        pop     esi ecx ebx
1906
        ret
3545 hidnplayr 1907
 
4527 hidnplayr 1908
  .error:
4528 hidnplayr 1909
        DEBUGF  DEBUG_NETWORK_ERROR, "SOCKET_notify: invalid socket ptr: 0x%x !\n", eax
4527 hidnplayr 1910
        ret
1911
 
1912
  .found:
1913
        test    [eax + SOCKET.state], SS_BLOCKED
4528 hidnplayr 1914
        jnz     .un_block
4527 hidnplayr 1915
 
5976 hidnplayr 1916
; Socket and thread exists and socket is of non blocking type.
4527 hidnplayr 1917
; We'll try to flag an event to the thread.
3545 hidnplayr 1918
        shl     ecx, 8
6908 ashmew2 1919
        or      [SLOT_BASE + ecx + APPDATA.event_mask], EVENT_NETWORK
3545 hidnplayr 1920
 
6413 hidnplayr 1921
        DEBUGF  DEBUG_NETWORK_VERBOSE, "SOCKET_notify: poking thread %u!\n", ebx
4527 hidnplayr 1922
        pop     esi ecx ebx
1923
        ret
3545 hidnplayr 1924
 
4527 hidnplayr 1925
 
4528 hidnplayr 1926
  .un_block:
5976 hidnplayr 1927
; Socket and thread exists and socket is of blocking type
4527 hidnplayr 1928
; We'll try to unblock it.
1929
        and     [eax + SOCKET.state], not SS_BLOCKED    ; Clear the 'socket is blocked' flag
7974 hidnplayr 1930
        mov     [esi + TASKDATA.state], TSTATE_RUNNING  ; Run the thread
3545 hidnplayr 1931
 
6908 ashmew2 1932
        DEBUGF  DEBUG_NETWORK_VERBOSE, "SOCKET_notify: Unblocked socket!\n"
4527 hidnplayr 1933
        pop     esi ecx ebx
3545 hidnplayr 1934
        ret
1935
 
1936
 
5976 hidnplayr 1937
;-----------------------------------------------------------------;
1938
;                                                                 ;
6011 hidnplayr 1939
; socket_alloc: Allocate memory for socket and put new socket     ;
1940
; into the list. Newly created socket is initialized with calling ;
1941
; PID and given a socket number.                                  ;
5976 hidnplayr 1942
;                                                                 ;
1943
;  IN:  /                                                         ;
1944
;                                                                 ;
1945
; OUT:  eax = socket ptr on success                               ;
1946
;       eax = 0 on error                                          ;
1947
;       edi = socket number on success                            ;
1948
;                                                                 ;
1949
;-----------------------------------------------------------------;
3545 hidnplayr 1950
align 4
6011 hidnplayr 1951
socket_alloc:
3545 hidnplayr 1952
 
1953
        push    ebx
1954
 
6413 hidnplayr 1955
        stdcall kernel_alloc, SOCKET_STRUCT_SIZE
5969 hidnplayr 1956
        or      eax, eax
1957
        jz      .nomem
3556 hidnplayr 1958
        DEBUGF  DEBUG_NETWORK_VERBOSE, "SOCKET_alloc: ptr=%x\n", eax
3545 hidnplayr 1959
 
1960
; zero-initialize allocated memory
1961
        push    eax
1962
        mov     edi, eax
6413 hidnplayr 1963
        mov     ecx, SOCKET_STRUCT_SIZE / 4
3545 hidnplayr 1964
        xor     eax, eax
3711 clevermous 1965
        rep stosd
3545 hidnplayr 1966
        pop     eax
1967
 
1968
; set send-and receive procedures to return -1
3658 hidnplayr 1969
        mov     [eax + SOCKET.snd_proc], .not_yet
1970
        mov     [eax + SOCKET.rcv_proc], .not_yet
3545 hidnplayr 1971
 
3647 hidnplayr 1972
        pusha
1973
        mov     ecx, socket_mutex
1974
        call    mutex_lock
1975
        popa
1976
 
3545 hidnplayr 1977
; find first free socket number and use it
1978
        mov     edi, [last_socket_num]
1979
  .next_socket_number:
1980
        inc     edi
1981
        jz      .next_socket_number     ; avoid socket nr 0
1982
        cmp     edi, -1
1983
        je      .next_socket_number     ; avoid socket nr -1
1984
        mov     ebx, net_sockets
1985
  .next_socket:
1986
        mov     ebx, [ebx + SOCKET.NextPtr]
1987
        test    ebx, ebx
1988
        jz      .last_socket
1989
 
1990
        cmp     [ebx + SOCKET.Number], edi
1991
        jne     .next_socket
1992
        jmp     .next_socket_number
1993
 
1994
  .last_socket:
1995
        mov     [last_socket_num], edi
1996
        mov     [eax + SOCKET.Number], edi
3556 hidnplayr 1997
        DEBUGF  DEBUG_NETWORK_VERBOSE, "SOCKET_alloc: number=%u\n", edi
3545 hidnplayr 1998
 
1999
; Fill in PID
2000
        mov     ebx, [TASK_BASE]
2001
        mov     ebx, [ebx + TASKDATA.pid]
2002
        mov     [eax + SOCKET.PID], ebx
2003
        mov     [eax + SOCKET.TID], ebx         ; currently TID = PID in kolibrios :(
2004
 
2005
; init mutex
2006
        pusha
2007
        lea     ecx, [eax + SOCKET.mutex]
2008
        call    mutex_init
2009
        popa
2010
 
2011
; add socket to the list by re-arranging some pointers
2012
        mov     ebx, [net_sockets + SOCKET.NextPtr]
2013
 
2014
        mov     [eax + SOCKET.PrevPtr], net_sockets
2015
        mov     [eax + SOCKET.NextPtr], ebx
2016
 
2017
        test    ebx, ebx
2018
        jz      @f
2019
 
2020
        pusha
2021
        lea     ecx, [ebx + SOCKET.mutex]
2022
        call    mutex_lock
2023
        popa
2024
 
2025
        mov     [ebx + SOCKET.PrevPtr], eax
2026
 
2027
        pusha
2028
        lea     ecx, [ebx + SOCKET.mutex]
2029
        call    mutex_unlock
2030
        popa
2031
       @@:
2032
 
2033
        mov     [net_sockets + SOCKET.NextPtr], eax
3647 hidnplayr 2034
 
2035
        pusha
2036
        mov     ecx, socket_mutex
2037
        call    mutex_unlock
2038
        popa
3545 hidnplayr 2039
        pop     ebx
2040
 
2041
        ret
2042
 
5969 hidnplayr 2043
  .nomem:
2044
        DEBUGF  DEBUG_NETWORK_ERROR, "SOCKET_alloc: Out of memory!\n"
2045
        pop     ebx
2046
        ret
2047
 
3658 hidnplayr 2048
  .not_yet:
3673 hidnplayr 2049
        mov     dword[esp+20], ENOTCONN
3658 hidnplayr 2050
        mov     dword[esp+32], -1
2051
        ret
3545 hidnplayr 2052
 
3658 hidnplayr 2053
 
5976 hidnplayr 2054
;-----------------------------------------------------------------;
2055
;                                                                 ;
6011 hidnplayr 2056
; socket_free: Free socket data memory and remove socket from     ;
2057
; the list. Caller should lock and unlock socket_mutex.           ;
5976 hidnplayr 2058
;                                                                 ;
2059
;  IN:  eax = socket ptr                                          ;
2060
;                                                                 ;
2061
; OUT:  /                                                         ;
2062
;                                                                 ;
2063
;-----------------------------------------------------------------;
3545 hidnplayr 2064
align 4
6011 hidnplayr 2065
socket_free:
3545 hidnplayr 2066
 
3556 hidnplayr 2067
        DEBUGF  DEBUG_NETWORK_VERBOSE, "SOCKET_free: %x\n", eax
3545 hidnplayr 2068
 
6011 hidnplayr 2069
        call    socket_check
3545 hidnplayr 2070
        jz      .error
2071
 
2072
        push    ebx
2073
 
2074
        pusha
2075
        lea     ecx, [eax + SOCKET.mutex]
2076
        call    mutex_lock
2077
        popa
2078
 
5969 hidnplayr 2079
        cmp     [eax + SOCKET.Type], SOCK_STREAM
2080
        jne     .no_stream
3545 hidnplayr 2081
 
2082
        mov     ebx, eax
5969 hidnplayr 2083
        cmp     [eax + STREAM_SOCKET.rcv.start_ptr], 0
2084
        je      @f
2085
        stdcall free_kernel_space, [eax + STREAM_SOCKET.rcv.start_ptr]
2086
  @@:
2087
        cmp     [ebx + STREAM_SOCKET.snd.start_ptr], 0
2088
        je      @f
2089
        stdcall free_kernel_space, [ebx + STREAM_SOCKET.snd.start_ptr]
2090
  @@:
3545 hidnplayr 2091
        mov     eax, ebx
5969 hidnplayr 2092
  .no_stream:
3545 hidnplayr 2093
 
3652 hidnplayr 2094
        DEBUGF  DEBUG_NETWORK_VERBOSE, "SOCKET_free: freeing socket %x\n", eax
3545 hidnplayr 2095
        push    eax                             ; this will be passed to kernel_free
2096
        mov     ebx, [eax + SOCKET.NextPtr]
2097
        mov     eax, [eax + SOCKET.PrevPtr]
2098
 
3556 hidnplayr 2099
        DEBUGF  DEBUG_NETWORK_VERBOSE, "SOCKET_free: linking socket %x to socket %x\n", eax, ebx
3545 hidnplayr 2100
 
2101
        test    eax, eax
2102
        jz      @f
2103
        mov     [eax + SOCKET.NextPtr], ebx
2104
       @@:
2105
 
2106
        test    ebx, ebx
2107
        jz      @f
2108
        mov     [ebx + SOCKET.PrevPtr], eax
2109
       @@:
2110
 
2111
        call    kernel_free
2112
        pop     ebx
2113
 
3652 hidnplayr 2114
        DEBUGF  DEBUG_NETWORK_VERBOSE, "SOCKET_free: success!\n"
2115
 
2116
  .error:
3545 hidnplayr 2117
        ret
2118
 
5969 hidnplayr 2119
  .error1:
2120
        pop     ebx
5976 hidnplayr 2121
        DEBUGF  DEBUG_NETWORK_ERROR, "SOCKET_free: error!\n"
5969 hidnplayr 2122
        DEBUGF  DEBUG_NETWORK_ERROR, "socket ptr=0x%x caller=0x%x\n", eax, [esp]
2123
        ret
2124
 
5976 hidnplayr 2125
;-----------------------------------------------------------------;
2126
;                                                                 ;
6011 hidnplayr 2127
; socket_fork: Create a child socket.                             ;
5976 hidnplayr 2128
;                                                                 ;
2129
;  IN:  ebx = socket number                                       ;
2130
;                                                                 ;
2131
; OUT:  eax = child socket number on success                      ;
2132
;       eax = 0 on error                                          ;
2133
;                                                                 ;
2134
;-----------------------------------------------------------------;
3545 hidnplayr 2135
align 4
6011 hidnplayr 2136
socket_fork:
3545 hidnplayr 2137
 
3556 hidnplayr 2138
        DEBUGF  DEBUG_NETWORK_VERBOSE, "SOCKET_fork: %x\n", ebx
3545 hidnplayr 2139
 
2140
; Exit if backlog queue is full
2141
        mov     eax, [ebx + SOCKET_QUEUE_LOCATION + queue.size]
2142
        cmp     ax, [ebx + SOCKET.backlog]
2143
        jae     .fail
2144
 
2145
; Allocate new socket
2146
        push    ebx
6011 hidnplayr 2147
        call    socket_alloc
3545 hidnplayr 2148
        pop     ebx
4535 hidnplayr 2149
        test    eax, eax
3545 hidnplayr 2150
        jz      .fail
2151
 
2152
        push    eax
2153
        mov     esi, esp
2154
        add_to_queue (ebx + SOCKET_QUEUE_LOCATION), MAX_backlog, 4, .fail2
2155
        pop     eax
2156
 
2157
; Copy structure from current socket to new
3817 hidnplayr 2158
; We start at PID to preserve the socket num, 2 pointers and mutex
2159
; TID will be filled in later
3545 hidnplayr 2160
        lea     esi, [ebx + SOCKET.PID]
2161
        lea     edi, [eax + SOCKET.PID]
2162
        mov     ecx, (SOCKET_QUEUE_LOCATION - SOCKET.PID + 3)/4
3711 clevermous 2163
        rep movsd
3545 hidnplayr 2164
 
2165
        and     [eax + SOCKET.options], not SO_ACCEPTCON
2166
 
3817 hidnplayr 2167
; Notify owner of parent socket
2168
        push    eax
2169
        mov     eax, ebx
6011 hidnplayr 2170
        call    socket_notify
3817 hidnplayr 2171
        pop     eax
2172
 
3545 hidnplayr 2173
        ret
2174
 
2175
  .fail2:
2176
        add     esp, 4+4+4
2177
  .fail:
3556 hidnplayr 2178
        DEBUGF  DEBUG_NETWORK_ERROR, "SOCKET_fork: failed\n"
3545 hidnplayr 2179
        xor     eax, eax
2180
        ret
2181
 
2182
 
5976 hidnplayr 2183
;-----------------------------------------------------------------;
2184
;                                                                 ;
6011 hidnplayr 2185
; socket_num_to_ptr: Get socket structure address by its number.  ;
5976 hidnplayr 2186
;                                                                 ;
2187
;  IN:  ecx = socket number                                       ;
2188
;                                                                 ;
2189
; OUT:  eax = socket ptr                                          ;
2190
;       eax = 0 on error                                          ;
2191
;                                                                 ;
2192
;-----------------------------------------------------------------;
3545 hidnplayr 2193
align 4
6011 hidnplayr 2194
socket_num_to_ptr:
3545 hidnplayr 2195
 
3556 hidnplayr 2196
        DEBUGF  DEBUG_NETWORK_VERBOSE, "SOCKET_num_to_ptr: num=%u ", ecx
3545 hidnplayr 2197
 
3647 hidnplayr 2198
        pusha
2199
        mov     ecx, socket_mutex
2200
        call    mutex_lock
2201
        popa
2202
 
3545 hidnplayr 2203
        mov     eax, net_sockets
2204
  .next_socket:
2205
        mov     eax, [eax + SOCKET.NextPtr]
5969 hidnplayr 2206
        test    eax, eax
3545 hidnplayr 2207
        jz      .error
2208
        cmp     [eax + SOCKET.Number], ecx
2209
        jne     .next_socket
2210
 
3647 hidnplayr 2211
        pusha
2212
        mov     ecx, socket_mutex
2213
        call    mutex_unlock
2214
        popa
2215
 
3556 hidnplayr 2216
        DEBUGF  DEBUG_NETWORK_VERBOSE, "ptr=%x\n", eax
3545 hidnplayr 2217
        ret
2218
 
2219
  .error:
3647 hidnplayr 2220
        pusha
2221
        mov     ecx, socket_mutex
2222
        call    mutex_unlock
2223
        popa
2224
 
4574 hidnplayr 2225
        DEBUGF  DEBUG_NETWORK_ERROR, "SOCKET_num_to_ptr: socket %u not found!\n", eax
2226
        DEBUGF  DEBUG_NETWORK_ERROR, "SOCKET_num_to_ptr: caller = 0x%x\n", [esp]
3545 hidnplayr 2227
        ret
2228
 
2229
 
5976 hidnplayr 2230
;-----------------------------------------------------------------;
2231
;                                                                 ;
6011 hidnplayr 2232
; socket_ptr_to_num: Get socket number by its address.            ;
5976 hidnplayr 2233
;                                                                 ;
2234
;  IN:  eax = socket ptr                                          ;
2235
;                                                                 ;
2236
; OUT:  eax = socket number                                       ;
2237
;       eax = 0 on error                                          ;
2238
;       ZF = set on error                                         ;
2239
;                                                                 ;
2240
;-----------------------------------------------------------------;
3545 hidnplayr 2241
align 4
6011 hidnplayr 2242
socket_ptr_to_num:
3545 hidnplayr 2243
 
3556 hidnplayr 2244
        DEBUGF  DEBUG_NETWORK_VERBOSE, "SOCKET_ptr_to_num: ptr=%x ", eax
3545 hidnplayr 2245
 
6011 hidnplayr 2246
        call    socket_check
3545 hidnplayr 2247
        jz      .error
2248
 
2249
        mov     eax, [eax + SOCKET.Number]
2250
 
3556 hidnplayr 2251
        DEBUGF  DEBUG_NETWORK_VERBOSE, "num=%u\n", eax
3545 hidnplayr 2252
        ret
2253
 
2254
  .error:
3556 hidnplayr 2255
        DEBUGF  DEBUG_NETWORK_ERROR, "SOCKET_ptr_to_num: not found\n", eax
3545 hidnplayr 2256
        ret
2257
 
2258
 
5976 hidnplayr 2259
;-----------------------------------------------------------------;
2260
;                                                                 ;
6011 hidnplayr 2261
; socket_check: Checks if the given ptr is really a socket ptr.   ;
5976 hidnplayr 2262
;                                                                 ;
2263
;  IN:  eax = socket ptr                                          ;
2264
;                                                                 ;
2265
; OUT:  eax = 0 on error                                          ;
2266
;       ZF = set on error                                         ;
2267
;                                                                 ;
2268
;-----------------------------------------------------------------;
3545 hidnplayr 2269
align 4
6011 hidnplayr 2270
socket_check:
3545 hidnplayr 2271
 
3556 hidnplayr 2272
        DEBUGF  DEBUG_NETWORK_VERBOSE, "SOCKET_check: %x\n", eax
3545 hidnplayr 2273
 
5969 hidnplayr 2274
        test    eax, eax
2275
        jz      .error
3545 hidnplayr 2276
        push    ebx
2277
        mov     ebx, net_sockets
2278
 
2279
  .next_socket:
2280
        mov     ebx, [ebx + SOCKET.NextPtr]
2281
        or      ebx, ebx
2282
        jz      .done
2283
        cmp     ebx, eax
2284
        jnz     .next_socket
2285
 
2286
  .done:
2287
        mov     eax, ebx
2288
        test    eax, eax
2289
        pop     ebx
5969 hidnplayr 2290
        ret
3545 hidnplayr 2291
 
5969 hidnplayr 2292
  .error:
5976 hidnplayr 2293
        DEBUGF  DEBUG_NETWORK_ERROR, "SOCKET_check: called with argument 0\n"
5969 hidnplayr 2294
        DEBUGF  DEBUG_NETWORK_ERROR, "stack: 0x%x, 0x%x, 0x%x\n", [esp], [esp+4], [esp+8]
3545 hidnplayr 2295
        ret
2296
 
2297
 
2298
 
5976 hidnplayr 2299
;-----------------------------------------------------------------;
2300
;                                                                 ;
6011 hidnplayr 2301
; socket_check_owner: Check if the caller app owns the socket.    ;
5976 hidnplayr 2302
;                                                                 ;
2303
;  IN:  eax = socket ptr                                          ;
2304
;                                                                 ;
2305
; OUT:  ZF = true/false                                           ;
2306
;                                                                 ;
2307
;-----------------------------------------------------------------;
3545 hidnplayr 2308
align 4
6011 hidnplayr 2309
socket_check_owner:
3545 hidnplayr 2310
 
3556 hidnplayr 2311
        DEBUGF  DEBUG_NETWORK_VERBOSE, "SOCKET_check_owner: %x\n", eax
3545 hidnplayr 2312
 
2313
        push    ebx
2314
        mov     ebx, [TASK_BASE]
2315
        mov     ebx, [ebx + TASKDATA.pid]
2316
        cmp     [eax + SOCKET.PID], ebx
3711 clevermous 2317
        pop     ebx
3545 hidnplayr 2318
 
2319
        ret
2320
 
2321
 
2322
 
2323
 
5976 hidnplayr 2324
;-----------------------------------------------------------------;
2325
;                                                                 ;
6011 hidnplayr 2326
; socket_process_end: Kernel calls this function when a certain   ;
2327
; process ends. This function will check if the process had any   ;
2328
; open sockets and update them accordingly (clean up).            ;
5976 hidnplayr 2329
;                                                                 ;
2330
;  IN:  edx = pid                                                 ;
2331
;                                                                 ;
2332
; OUT:  /                                                         ;
2333
;                                                                 ;
2334
;-----------------------------------------------------------------;
3545 hidnplayr 2335
align 4
6011 hidnplayr 2336
socket_process_end:
3545 hidnplayr 2337
 
4436 hidnplayr 2338
        ret     ; FIXME
2339
 
4056 hidnplayr 2340
        cmp     [net_sockets + SOCKET.NextPtr], 0       ; Are there any active sockets at all?
2341
        je      .quickret                               ; nope, exit immediately
2342
 
2343
; TODO: run the following code in another thread, to avoid deadlock
2344
 
3556 hidnplayr 2345
        DEBUGF  DEBUG_NETWORK_VERBOSE, "SOCKET_process_end: %x\n", edx
3545 hidnplayr 2346
 
3647 hidnplayr 2347
        pusha
2348
        mov     ecx, socket_mutex
2349
        call    mutex_lock
2350
        popa
2351
 
3545 hidnplayr 2352
        push    ebx
2353
        mov     ebx, net_sockets
2354
 
2355
  .next_socket:
2356
        mov     ebx, [ebx + SOCKET.NextPtr]
2357
  .next_socket_test:
2358
        test    ebx, ebx
2359
        jz      .done
2360
 
2361
        cmp     [ebx + SOCKET.PID], edx
2362
        jne     .next_socket
2363
 
3556 hidnplayr 2364
        DEBUGF  DEBUG_NETWORK_VERBOSE, "SOCKET_process_end: killing socket %x\n", ebx
3545 hidnplayr 2365
 
2366
        mov     [ebx + SOCKET.PID], 0
2367
        mov     eax, ebx
2368
        mov     ebx, [ebx + SOCKET.NextPtr]
3648 hidnplayr 2369
 
3545 hidnplayr 2370
        pusha
3652 hidnplayr 2371
        cmp     [eax + SOCKET.Domain], AF_INET4
2372
        jne     .free
2373
 
2374
        cmp     [eax + SOCKET.Protocol], IP_PROTO_TCP
2375
        jne     .free
2376
 
6011 hidnplayr 2377
        call    tcp_disconnect
3652 hidnplayr 2378
        jmp     .closed
2379
 
2380
  .free:
6011 hidnplayr 2381
        call    socket_free
3652 hidnplayr 2382
 
2383
  .closed:
3545 hidnplayr 2384
        popa
2385
        jmp     .next_socket_test
2386
 
2387
  .done:
2388
        pop     ebx
2389
 
3647 hidnplayr 2390
        pusha
2391
        mov     ecx, socket_mutex
2392
        call    mutex_unlock
2393
        popa
2394
 
4056 hidnplayr 2395
  .quickret:
3545 hidnplayr 2396
        ret
2397
 
2398
 
2399
 
2400
 
5976 hidnplayr 2401
;-----------------------------------------------------------------;
2402
;                                                                 ;
6011 hidnplayr 2403
; socket_is_connecting: Update socket state.                      ;
5976 hidnplayr 2404
;                                                                 ;
2405
;  IN:  eax = socket ptr                                          ;
2406
;                                                                 ;
2407
;  OUT: /                                                         ;
2408
;                                                                 ;
2409
;-----------------------------------------------------------------;
3545 hidnplayr 2410
align 4
6011 hidnplayr 2411
socket_is_connecting:
3545 hidnplayr 2412
 
3556 hidnplayr 2413
        DEBUGF  DEBUG_NETWORK_VERBOSE, "SOCKET_is_connecting: %x\n", eax
3545 hidnplayr 2414
 
4025 hidnplayr 2415
        and     [eax + SOCKET.state], not (SS_ISCONNECTED + SS_ISDISCONNECTING + SS_ISCONFIRMING)
2416
        or      [eax + SOCKET.state], SS_ISCONNECTING
2417
        ret
3545 hidnplayr 2418
 
2419
 
2420
 
5976 hidnplayr 2421
;-----------------------------------------------------------------;
2422
;                                                                 ;
6011 hidnplayr 2423
; socket_is_connected: Update socket state.                       ;
5976 hidnplayr 2424
;                                                                 ;
2425
;  IN:  eax = socket ptr                                          ;
2426
;                                                                 ;
2427
;  OUT: /                                                         ;
2428
;                                                                 ;
2429
;-----------------------------------------------------------------;
3545 hidnplayr 2430
align 4
6011 hidnplayr 2431
socket_is_connected:
3545 hidnplayr 2432
 
3556 hidnplayr 2433
        DEBUGF  DEBUG_NETWORK_VERBOSE, "SOCKET_is_connected: %x\n", eax
3545 hidnplayr 2434
 
3674 hidnplayr 2435
        and     [eax + SOCKET.state], not (SS_ISCONNECTING + SS_ISDISCONNECTING + SS_ISCONFIRMING)
2436
        or      [eax + SOCKET.state], SS_ISCONNECTED
6011 hidnplayr 2437
        jmp     socket_notify
3545 hidnplayr 2438
 
2439
 
2440
 
2441
 
5976 hidnplayr 2442
;-----------------------------------------------------------------;
2443
;                                                                 ;
6011 hidnplayr 2444
; socket_is_disconnecting: Update socket state.                   ;
5976 hidnplayr 2445
;                                                                 ;
2446
;  IN:  eax = socket ptr                                          ;
2447
;                                                                 ;
2448
;  OUT: /                                                         ;
2449
;                                                                 ;
2450
;-----------------------------------------------------------------;
3545 hidnplayr 2451
align 4
6011 hidnplayr 2452
socket_is_disconnecting:
3545 hidnplayr 2453
 
3556 hidnplayr 2454
        DEBUGF  DEBUG_NETWORK_VERBOSE, "SOCKET_is_disconnecting: %x\n", eax
3545 hidnplayr 2455
 
3674 hidnplayr 2456
        and     [eax + SOCKET.state], not (SS_ISCONNECTING)
2457
        or      [eax + SOCKET.state], SS_ISDISCONNECTING + SS_CANTRCVMORE + SS_CANTSENDMORE
6011 hidnplayr 2458
        jmp     socket_notify
3545 hidnplayr 2459
 
2460
 
2461
 
5976 hidnplayr 2462
;-----------------------------------------------------------------;
2463
;                                                                 ;
6011 hidnplayr 2464
; socket_is_disconnected: Update socket state.                    ;
5976 hidnplayr 2465
;                                                                 ;
2466
;  IN:  eax = socket ptr                                          ;
2467
;                                                                 ;
2468
;  OUT: /                                                         ;
2469
;                                                                 ;
2470
;-----------------------------------------------------------------;
3545 hidnplayr 2471
align 4
6011 hidnplayr 2472
socket_is_disconnected:
3545 hidnplayr 2473
 
3556 hidnplayr 2474
        DEBUGF  DEBUG_NETWORK_VERBOSE, "SOCKET_is_disconnected: %x\n", eax
3545 hidnplayr 2475
 
3674 hidnplayr 2476
        and     [eax + SOCKET.state], not (SS_ISCONNECTING + SS_ISCONNECTED + SS_ISDISCONNECTING)
2477
        or      [eax + SOCKET.state], SS_CANTRCVMORE + SS_CANTSENDMORE
6011 hidnplayr 2478
        jmp     socket_notify
3545 hidnplayr 2479
 
2480
 
2481
 
5976 hidnplayr 2482
;-----------------------------------------------------------------;
2483
;                                                                 ;
6011 hidnplayr 2484
; socket_cant_recv_more: Update socket state.                     ;
5976 hidnplayr 2485
;                                                                 ;
2486
;  IN:  eax = socket ptr                                          ;
2487
;                                                                 ;
2488
;  OUT: /                                                         ;
2489
;                                                                 ;
2490
;-----------------------------------------------------------------;
3545 hidnplayr 2491
align 4
6011 hidnplayr 2492
socket_cant_recv_more:
3545 hidnplayr 2493
 
3556 hidnplayr 2494
        DEBUGF  DEBUG_NETWORK_VERBOSE, "SOCKET_cant_recv_more: %x\n", eax
3545 hidnplayr 2495
 
3674 hidnplayr 2496
        or      [eax + SOCKET.state], SS_CANTRCVMORE
6011 hidnplayr 2497
        jmp     socket_notify
3545 hidnplayr 2498
 
3565 hidnplayr 2499
 
3545 hidnplayr 2500
 
5976 hidnplayr 2501
;-----------------------------------------------------------------;
2502
;                                                                 ;
6011 hidnplayr 2503
; socket_cant_send_more: Update socket state.                     ;
5976 hidnplayr 2504
;                                                                 ;
2505
;  IN:  eax = socket ptr                                          ;
2506
;                                                                 ;
2507
;  OUT: /                                                         ;
2508
;                                                                 ;
2509
;-----------------------------------------------------------------;
3545 hidnplayr 2510
align 4
6011 hidnplayr 2511
socket_cant_send_more:
3545 hidnplayr 2512
 
3556 hidnplayr 2513
        DEBUGF  DEBUG_NETWORK_VERBOSE, "SOCKET_cant_send_more: %x\n", eax
3545 hidnplayr 2514
 
3674 hidnplayr 2515
        or      [eax + SOCKET.state], SS_CANTSENDMORE
3658 hidnplayr 2516
        mov     [eax + SOCKET.snd_proc], .notconn
6011 hidnplayr 2517
        jmp     socket_notify
3545 hidnplayr 2518
 
3658 hidnplayr 2519
  .notconn:
3673 hidnplayr 2520
        mov     dword[esp+20], ENOTCONN
3658 hidnplayr 2521
        mov     dword[esp+32], -1
5356 serge 2522
        ret