Subversion Repositories Kolibri OS

Rev

Rev 9993 | Details | Compare with Previous | Last modification | View Log | RSS feed

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