Subversion Repositories Kolibri OS

Rev

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

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