Subversion Repositories Kolibri OS

Rev

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

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