Subversion Repositories Kolibri OS

Rev

Rev 4030 | Rev 4056 | 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/..
31
        Type                    dd ? ; RAW/STREAM/DGRAP
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
95
        SND_CWND                dd ?
96
        SND_SSTHRESH            dd ?
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
        temp_bits               db ?
145
                                rb 3 ; align
146
 
4021 hidnplayr 147
 
3545 hidnplayr 148
ends
149
 
150
struct  UDP_SOCKET              IP_SOCKET
151
 
152
        LocalPort               dw ? ; network byte order
153
        RemotePort              dw ? ; network byte order
154
 
155
ends
156
 
157
 
158
struct  ICMP_SOCKET             IP_SOCKET
159
 
160
        Identifier              dw ?
161
 
162
ends
163
 
164
 
165
struct  RING_BUFFER
166
 
167
        mutex                   MUTEX
168
        start_ptr               dd ? ; Pointer to start of buffer
169
        end_ptr                 dd ? ; pointer to end of buffer
170
        read_ptr                dd ? ; Read pointer
171
        write_ptr               dd ? ; Write pointer
172
        size                    dd ? ; Number of bytes buffered
173
 
174
ends
175
 
176
struct  STREAM_SOCKET           TCP_SOCKET
177
 
178
        rcv                     RING_BUFFER
179
        snd                     RING_BUFFER
180
 
181
ends
182
 
183
struct  socket_queue_entry
184
 
185
        data_ptr                dd ?
186
        buf_ptr                 dd ?
187
        data_size               dd ?
188
 
189
ends
190
 
191
 
192
SOCKETBUFFSIZE          = 4096     ; in bytes
193
 
194
SOCKET_QUEUE_SIZE       = 10       ; maximum number of incoming packets queued for 1 socket
195
; the incoming packet queue for sockets is placed in the socket struct itself, at this location from start
196
SOCKET_QUEUE_LOCATION   = (SOCKETBUFFSIZE - SOCKET_QUEUE_SIZE*sizeof.socket_queue_entry - sizeof.queue)
197
 
198
uglobal
3698 hidnplayr 199
align 4
200
 
3545 hidnplayr 201
        net_sockets     rd 4
202
        last_socket_num dd ?
203
        last_UDP_port   dw ? ; These values give the number of the last used ephemeral port
204
        last_TCP_port   dw ? ;
3647 hidnplayr 205
        socket_mutex    MUTEX
3698 hidnplayr 206
 
3545 hidnplayr 207
endg
208
 
209
 
210
;-----------------------------------------------------------------
211
;
212
; SOCKET_init
213
;
214
;-----------------------------------------------------------------
215
macro   SOCKET_init {
216
 
217
        xor     eax, eax
218
        mov     edi, net_sockets
219
        mov     ecx, 5
3711 clevermous 220
        rep stosd
3545 hidnplayr 221
 
222
       @@:
223
        pseudo_random eax
3600 hidnplayr 224
        cmp     ax, EPHEMERAL_PORT_MIN
3545 hidnplayr 225
        jb      @r
3600 hidnplayr 226
        cmp     ax, EPHEMERAL_PORT_MAX
3545 hidnplayr 227
        ja      @r
228
        xchg    al, ah
229
        mov     [last_UDP_port], ax
230
 
231
       @@:
232
        pseudo_random eax
3600 hidnplayr 233
        cmp     ax, EPHEMERAL_PORT_MIN
3545 hidnplayr 234
        jb      @r
3600 hidnplayr 235
        cmp     ax, EPHEMERAL_PORT_MAX
3545 hidnplayr 236
        ja      @r
237
        xchg    al, ah
238
        mov     [last_TCP_port], ax
239
 
3647 hidnplayr 240
        mov     ecx, socket_mutex
241
        call    mutex_init
242
 
3545 hidnplayr 243
}
244
 
245
;-----------------------------------------------------------------
246
;
247
; Socket API (function 74)
248
;
249
;-----------------------------------------------------------------
250
align 4
251
sys_socket:
252
 
3673 hidnplayr 253
        mov     dword[esp+20], 0        ; Set error code to 0
3659 hidnplayr 254
 
3545 hidnplayr 255
        cmp     ebx, 255
256
        jz      SOCKET_debug
257
 
258
        cmp     ebx, .number
3658 hidnplayr 259
        ja      .error
3545 hidnplayr 260
        jmp     dword [.table + 4*ebx]
261
 
262
  .table:
263
        dd      SOCKET_open     ; 0
264
        dd      SOCKET_close    ; 1
265
        dd      SOCKET_bind     ; 2
266
        dd      SOCKET_listen   ; 3
267
        dd      SOCKET_connect  ; 4
268
        dd      SOCKET_accept   ; 5
269
        dd      SOCKET_send     ; 6
270
        dd      SOCKET_receive  ; 7
271
        dd      SOCKET_set_opt  ; 8
272
        dd      SOCKET_get_opt  ; 9
273
        dd      SOCKET_pair     ; 10
274
  .number = ($ - .table) / 4 - 1
275
 
3658 hidnplayr 276
  .error:
277
        mov     dword[esp+32], -1
3673 hidnplayr 278
        mov     dword[esp+20], EINVAL
3545 hidnplayr 279
 
280
        ret
281
 
282
;-----------------------------------------------------------------
283
;
284
; SOCKET_open
285
;
286
;  IN:  domain in ecx
287
;       type in edx
288
;       protocol in esi
289
;  OUT: eax is socket num, -1 on error
290
;
291
;-----------------------------------------------------------------
292
align 4
293
SOCKET_open:
294
 
3556 hidnplayr 295
        DEBUGF  DEBUG_NETWORK_VERBOSE, "SOCKET_open: domain=%u type=%u protocol=%x ", ecx, edx, esi
3545 hidnplayr 296
 
297
        push    ecx edx esi
298
        call    SOCKET_alloc
299
        pop     esi edx ecx
3658 hidnplayr 300
        jz      .nobuffs
3545 hidnplayr 301
 
302
        mov     [esp+32], edi                   ; return socketnumber
3556 hidnplayr 303
        DEBUGF  DEBUG_NETWORK_VERBOSE, "socknum=%u\n", edi
3545 hidnplayr 304
 
3705 hidnplayr 305
        test    edx, SO_NONBLOCK
306
        jz      @f
307
        or      [eax + SOCKET.options], SO_NONBLOCK
308
        and     edx, not SO_NONBLOCK
309
  @@:
3545 hidnplayr 310
 
311
        mov     [eax + SOCKET.Domain], ecx
312
        mov     [eax + SOCKET.Type], edx
313
        mov     [eax + SOCKET.Protocol], esi
4030 hidnplayr 314
        mov     [eax + SOCKET.connect_proc], connect_notsupp
3545 hidnplayr 315
 
316
        cmp     ecx, AF_INET4
317
        jne     .no_inet4
318
 
319
        cmp     edx, SOCK_DGRAM
320
        je      .udp
321
 
322
        cmp     edx, SOCK_STREAM
323
        je      .tcp
324
 
325
        cmp     edx, SOCK_RAW
326
        je      .raw
327
 
328
  .no_inet4:
329
        cmp     ecx, AF_PPP
330
        jne     .no_ppp
331
 
332
        cmp     esi, PPP_PROTO_ETHERNET
333
        je      .pppoe
334
 
335
  .no_ppp:
3658 hidnplayr 336
  .unsupported:
337
        push    eax
338
        call    SOCKET_free
339
        pop     eax
3673 hidnplayr 340
        mov     dword[esp+20], EOPNOTSUPP
3658 hidnplayr 341
        mov     dword[esp+32], -1
3545 hidnplayr 342
        ret
343
 
3658 hidnplayr 344
  .nobuffs:
3673 hidnplayr 345
        mov     dword[esp+20], ENOBUFS
3658 hidnplayr 346
        mov     dword[esp+32], -1
347
        ret
348
 
3545 hidnplayr 349
  .raw:
350
        test    esi, esi       ; IP_PROTO_IP
3658 hidnplayr 351
        jz      .raw_ip
3545 hidnplayr 352
 
353
        cmp     esi, IP_PROTO_ICMP
3658 hidnplayr 354
        je      .raw_icmp
3545 hidnplayr 355
 
3658 hidnplayr 356
        jmp     .unsupported
3545 hidnplayr 357
 
358
align 4
359
  .udp:
360
        mov     [eax + SOCKET.Protocol], IP_PROTO_UDP
361
        mov     [eax + SOCKET.snd_proc], SOCKET_send_udp
362
        mov     [eax + SOCKET.rcv_proc], SOCKET_receive_dgram
4030 hidnplayr 363
        mov     [eax + SOCKET.connect_proc], UDP_connect
3545 hidnplayr 364
        ret
365
 
366
align 4
367
  .tcp:
368
        mov     [eax + SOCKET.Protocol], IP_PROTO_TCP
369
        mov     [eax + SOCKET.snd_proc], SOCKET_send_tcp
370
        mov     [eax + SOCKET.rcv_proc], SOCKET_receive_stream
4030 hidnplayr 371
        mov     [eax + SOCKET.connect_proc], TCP_connect
3545 hidnplayr 372
 
373
        TCP_init_socket eax
374
        ret
375
 
376
 
377
align 4
3658 hidnplayr 378
  .raw_ip:
3545 hidnplayr 379
        mov     [eax + SOCKET.snd_proc], SOCKET_send_ip
380
        mov     [eax + SOCKET.rcv_proc], SOCKET_receive_dgram
4030 hidnplayr 381
        mov     [eax + SOCKET.connect_proc], IPv4_connect
3545 hidnplayr 382
        ret
383
 
384
 
385
align 4
3658 hidnplayr 386
  .raw_icmp:
3545 hidnplayr 387
        mov     [eax + SOCKET.snd_proc], SOCKET_send_icmp
388
        mov     [eax + SOCKET.rcv_proc], SOCKET_receive_dgram
4030 hidnplayr 389
        mov     [eax + SOCKET.connect_proc], IPv4_connect
3545 hidnplayr 390
        ret
391
 
392
align 4
393
  .pppoe:
394
        push    eax
395
        init_queue (eax + SOCKET_QUEUE_LOCATION)        ; Set up data receiving queue
396
        pop     eax
397
 
398
        mov     [eax + SOCKET.snd_proc], SOCKET_send_pppoe
399
        mov     [eax + SOCKET.rcv_proc], SOCKET_receive_dgram
400
        ret
401
 
402
 
403
;-----------------------------------------------------------------
404
;
405
; SOCKET_bind
406
;
407
;  IN:  socket number in ecx
408
;       pointer to sockaddr struct in edx
409
;       length of that struct in esi
410
;  OUT: 0 on success
411
;
412
;-----------------------------------------------------------------
413
align 4
414
SOCKET_bind:
415
 
3556 hidnplayr 416
        DEBUGF  DEBUG_NETWORK_VERBOSE, "SOCKET_bind: socknum=%u sockaddr=%x length=%u\n", ecx, edx, esi
3545 hidnplayr 417
 
418
        call    SOCKET_num_to_ptr
3658 hidnplayr 419
        jz      .invalid
3545 hidnplayr 420
 
421
        cmp     esi, 2
3658 hidnplayr 422
        jb      .invalid
3545 hidnplayr 423
 
4052 hidnplayr 424
        cmp     [eax + UDP_SOCKET.LocalPort], 0         ; Socket can only be bound once
425
        jnz     .invalid
426
 
3545 hidnplayr 427
        cmp     word [edx], AF_INET4
428
        je      .af_inet4
429
 
430
        cmp     word [edx], AF_LOCAL
431
        je      .af_local
432
 
3658 hidnplayr 433
  .notsupp:
3673 hidnplayr 434
        mov     dword[esp+20], EOPNOTSUPP
3658 hidnplayr 435
        mov     dword[esp+32], -1
436
        ret
3545 hidnplayr 437
 
3658 hidnplayr 438
  .invalid:
3673 hidnplayr 439
        mov     dword[esp+20], EINVAL
3658 hidnplayr 440
        mov     dword[esp+32], -1
441
        ret
442
 
3545 hidnplayr 443
  .af_local:
444
        ; TODO: write code here
3658 hidnplayr 445
        mov     dword[esp+32], 0
3545 hidnplayr 446
        ret
447
 
448
  .af_inet4:
449
        cmp     esi, 6
3658 hidnplayr 450
        jb      .invalid
3545 hidnplayr 451
 
452
        cmp     [eax + SOCKET.Protocol], IP_PROTO_UDP
453
        je      .udp
454
 
455
        cmp     [eax + SOCKET.Protocol], IP_PROTO_TCP
456
        je      .tcp
457
 
3658 hidnplayr 458
        jmp     .notsupp
3545 hidnplayr 459
 
460
  .tcp:
461
  .udp:
462
 
4052 hidnplayr 463
        pushd   [edx + 4]                       ; First, fill in the IP
464
        popd    [eax + IP_SOCKET.LocalIP]
3545 hidnplayr 465
 
4052 hidnplayr 466
        mov     bx, [edx + 2]                   ; Did caller specify a local port?
467
        test    bx, bx
468
        jnz     .just_check
469
        call    SOCKET_find_port                ; Nope, find an ephemeral one
470
        jmp     .done
471
 
472
  .just_check:
473
        call    SOCKET_check_port               ; Yes, check if it's still available
474
        jz      .addrinuse                      ; ZF is set by socket_check_port on error
475
 
476
  .done:
3556 hidnplayr 477
        DEBUGF  DEBUG_NETWORK_VERBOSE, "SOCKET_bind: local ip=%u.%u.%u.%u\n",\
3545 hidnplayr 478
        [eax + IP_SOCKET.LocalIP + 0]:1,[eax + IP_SOCKET.LocalIP + 1]:1,\
479
        [eax + IP_SOCKET.LocalIP + 2]:1,[eax + IP_SOCKET.LocalIP + 3]:1
480
 
3658 hidnplayr 481
        mov     dword[esp+32], 0
3545 hidnplayr 482
        ret
483
 
3658 hidnplayr 484
  .addrinuse:
485
        mov     dword[esp+32], -1
3673 hidnplayr 486
        mov     dword[esp+20], EADDRINUSE
3658 hidnplayr 487
        ret
3545 hidnplayr 488
 
489
 
490
 
3658 hidnplayr 491
 
3545 hidnplayr 492
;-----------------------------------------------------------------
493
;
494
; SOCKET_connect
495
;
496
;  IN:  socket number in ecx
497
;       pointer to sockaddr struct in edx
498
;       length of that struct in esi
499
;  OUT: 0 on success
500
;
501
;-----------------------------------------------------------------
502
align 4
503
SOCKET_connect:
504
 
3556 hidnplayr 505
        DEBUGF  DEBUG_NETWORK_VERBOSE, "SOCKET_connect: socknum=%u sockaddr=%x length=%u\n", ecx, edx, esi
3545 hidnplayr 506
 
507
        call    SOCKET_num_to_ptr
3658 hidnplayr 508
        jz      .invalid
3545 hidnplayr 509
 
510
        cmp     esi, 8
3658 hidnplayr 511
        jb      .invalid
3545 hidnplayr 512
 
4025 hidnplayr 513
        cmp     [eax + SOCKET.state], SS_ISCONNECTING
514
        je      .already
515
 
516
        test    [eax + SOCKET.options], SO_ACCEPTCON
517
        jnz     .notsupp
518
 
4030 hidnplayr 519
        call    [eax + SOCKET.connect_proc]
3545 hidnplayr 520
 
4030 hidnplayr 521
        mov     dword[esp+20], ebx
522
        mov     dword[esp+32], eax
523
        ret
524
 
525
 
3658 hidnplayr 526
  .notsupp:
3673 hidnplayr 527
        mov     dword[esp+20], EOPNOTSUPP
3658 hidnplayr 528
        mov     dword[esp+32], -1
529
        ret
3545 hidnplayr 530
 
3658 hidnplayr 531
  .invalid:
3673 hidnplayr 532
        mov     dword[esp+20], EINVAL
3658 hidnplayr 533
        mov     dword[esp+32], -1
534
        ret
535
 
4025 hidnplayr 536
  .already:
537
        mov     dword[esp+20], EALREADY
538
        mov     dword[esp+32], -1
539
        ret
540
 
541
 
4030 hidnplayr 542
connect_notsupp:
543
        xor     eax, eax
544
        dec     eax
545
        mov     ebx, EOPNOTSUPP
3545 hidnplayr 546
        ret
547
 
4025 hidnplayr 548
 
3545 hidnplayr 549
;-----------------------------------------------------------------
550
;
551
; SOCKET_listen
552
;
553
;  IN:  socket number in ecx
554
;       backlog in edx
555
;  OUT: eax is socket num, -1 on error
556
;
557
;-----------------------------------------------------------------
558
align 4
559
SOCKET_listen:
560
 
3556 hidnplayr 561
        DEBUGF  DEBUG_NETWORK_VERBOSE, "SOCKET_listen: socknum=%u backlog=%u\n", ecx, edx
3545 hidnplayr 562
 
563
        call    SOCKET_num_to_ptr
3658 hidnplayr 564
        jz      .invalid
3545 hidnplayr 565
 
566
        cmp     [eax + SOCKET.Domain], AF_INET4
3658 hidnplayr 567
        jne     .notsupp
3545 hidnplayr 568
 
569
        cmp     [eax + SOCKET.Protocol], IP_PROTO_TCP
3658 hidnplayr 570
        jne     .invalid
3545 hidnplayr 571
 
572
        cmp     [eax + TCP_SOCKET.LocalPort], 0
3658 hidnplayr 573
        je      .already
3545 hidnplayr 574
 
575
        cmp     [eax + IP_SOCKET.LocalIP], 0
576
        jne     @f
3601 hidnplayr 577
        push    [IP_LIST + 4]           ;;; fixme!!!!
3545 hidnplayr 578
        pop     [eax + IP_SOCKET.LocalIP]
579
       @@:
580
 
581
        cmp     edx, MAX_backlog
582
        jbe     @f
583
        mov     edx, MAX_backlog
584
       @@:
585
 
586
        mov     [eax + SOCKET.backlog], dx
587
        or      [eax + SOCKET.options], SO_ACCEPTCON
588
        mov     [eax + TCP_SOCKET.t_state], TCPS_LISTEN
589
        mov     [eax + TCP_SOCKET.timer_keepalive], 0           ; disable keepalive timer
590
 
591
        push    eax
592
        init_queue (eax + SOCKET_QUEUE_LOCATION)                ; Set up sockets queue
593
        pop     eax
594
 
3658 hidnplayr 595
        mov     dword[esp+32], 0
596
        ret
3545 hidnplayr 597
 
3658 hidnplayr 598
  .notsupp:
3673 hidnplayr 599
        mov     dword[esp+20], EOPNOTSUPP
3658 hidnplayr 600
        mov     dword[esp+32], -1
3545 hidnplayr 601
        ret
602
 
3658 hidnplayr 603
  .invalid:
3673 hidnplayr 604
        mov     dword[esp+20], EINVAL
3658 hidnplayr 605
        mov     dword[esp+32], -1
606
        ret
3545 hidnplayr 607
 
3658 hidnplayr 608
  .already:
3673 hidnplayr 609
        mov     dword[esp+20], EALREADY
3658 hidnplayr 610
        mov     dword[esp+32], -1
611
        ret
612
 
613
 
3545 hidnplayr 614
;-----------------------------------------------------------------
615
;
616
; SOCKET_accept
617
;
618
;  IN:  socket number in ecx
619
;       addr in edx
620
;       addrlen in esi
621
;  OUT: eax is socket num, -1 on error
622
;
623
;-----------------------------------------------------------------
624
align 4
625
SOCKET_accept:
626
 
3556 hidnplayr 627
        DEBUGF  DEBUG_NETWORK_VERBOSE, "SOCKET_accept: socknum=%u sockaddr=%x length=%u\n", ecx, edx, esi
3545 hidnplayr 628
 
629
        call    SOCKET_num_to_ptr
3658 hidnplayr 630
        jz      .invalid
3545 hidnplayr 631
 
632
        test    [eax + SOCKET.options], SO_ACCEPTCON
3658 hidnplayr 633
        jz      .invalid
3545 hidnplayr 634
 
635
        cmp     [eax + SOCKET.Domain], AF_INET4
3658 hidnplayr 636
        jne     .notsupp
3545 hidnplayr 637
 
638
        cmp     [eax + SOCKET.Protocol], IP_PROTO_TCP
3658 hidnplayr 639
        jne     .invalid
3545 hidnplayr 640
 
641
  .loop:
642
        get_from_queue (eax + SOCKET_QUEUE_LOCATION), MAX_backlog, 4, .block
643
 
644
; Ok, we got a socket ptr
645
        mov     eax, [esi]
646
 
647
; Change thread ID to that of the current thread
648
        mov     ebx, [TASK_BASE]
649
        mov     ebx, [ebx + TASKDATA.pid]
650
        mov     [eax + SOCKET.TID], ebx
651
 
3817 hidnplayr 652
; Convert it to a socket number
653
        call    SOCKET_ptr_to_num
654
        jz      .invalid        ; FIXME ?
655
 
3545 hidnplayr 656
; and return it to caller
657
        mov     [esp+32], eax
658
        ret
659
 
660
  .block:
661
        test    [eax + SOCKET.options], SO_NONBLOCK
3658 hidnplayr 662
        jnz     .wouldblock
3545 hidnplayr 663
 
664
        call    SOCKET_block
665
        jmp     .loop
666
 
3658 hidnplayr 667
  .wouldblock:
3673 hidnplayr 668
        mov     dword[esp+20], EWOULDBLOCK
3658 hidnplayr 669
        mov     dword[esp+32], -1
670
        ret
671
 
672
  .invalid:
3673 hidnplayr 673
        mov     dword[esp+20], EINVAL
3658 hidnplayr 674
        mov     dword[esp+32], -1
675
        ret
676
 
677
  .notsupp:
3673 hidnplayr 678
        mov     dword[esp+20], EOPNOTSUPP
3658 hidnplayr 679
        mov     dword[esp+32], -1
680
        ret
681
 
3545 hidnplayr 682
;-----------------------------------------------------------------
683
;
684
; SOCKET_close
685
;
686
;  IN:  socket number in ecx
687
;  OUT: eax is socket num, -1 on error
688
;
689
;-----------------------------------------------------------------
690
align 4
691
SOCKET_close:
692
 
3556 hidnplayr 693
        DEBUGF  DEBUG_NETWORK_VERBOSE, "SOCKET_close: socknum=%u\n", ecx
3545 hidnplayr 694
 
695
        call    SOCKET_num_to_ptr
3658 hidnplayr 696
        jz      .invalid
3545 hidnplayr 697
 
3658 hidnplayr 698
        mov     dword[esp+32], 0                                ; The socket exists, so we will succeed in closing it.
3545 hidnplayr 699
 
700
        or      [eax + SOCKET.options], SO_NONBLOCK             ; Mark the socket as non blocking, we dont want it to block any longer!
701
 
702
        test    [eax + SOCKET.state], SS_BLOCKED                ; Is the socket still in blocked state?
703
        jz      @f
704
        call    SOCKET_notify.unblock                           ; Unblock it.
705
  @@:
706
 
707
        cmp     [eax + SOCKET.Domain], AF_INET4
708
        jne     .free
709
 
710
        cmp     [eax + SOCKET.Protocol], IP_PROTO_TCP
711
        je      .tcp
712
 
713
  .free:
714
        call    SOCKET_free
715
        ret
716
 
717
  .tcp:
718
        cmp     [eax + TCP_SOCKET.t_state], TCPS_SYN_RECEIVED    ; state must be LISTEN, SYN_SENT or CLOSED
719
        jb      .free
720
 
721
        call    TCP_usrclosed
722
        call    TCP_output      ;;;; Fixme: is this nescessary??
3646 hidnplayr 723
        call    SOCKET_free
3545 hidnplayr 724
 
725
        ret
726
 
727
 
3658 hidnplayr 728
  .invalid:
3673 hidnplayr 729
        mov     dword[esp+20], EINVAL
3658 hidnplayr 730
        mov     dword[esp+32], -1
731
        ret
732
 
733
 
3545 hidnplayr 734
;-----------------------------------------------------------------
735
;
736
; SOCKET_receive
737
;
738
;  IN:  socket number in ecx
739
;       addr to buffer in edx
740
;       length of buffer in esi
741
;       flags in edi
742
;  OUT: eax is number of bytes copied, -1 on error
743
;
744
;-----------------------------------------------------------------
745
align 4
746
SOCKET_receive:
747
 
3556 hidnplayr 748
        DEBUGF  DEBUG_NETWORK_VERBOSE, "SOCKET_receive: socknum=%u bufaddr=%x buflength=%u flags=%x\n", ecx, edx, esi, edi
3545 hidnplayr 749
 
750
        call    SOCKET_num_to_ptr
3658 hidnplayr 751
        jz      .invalid
3545 hidnplayr 752
 
3704 hidnplayr 753
  .loop:
754
        push    edi
3565 hidnplayr 755
        call    [eax + SOCKET.rcv_proc]
3704 hidnplayr 756
        pop     edi
3545 hidnplayr 757
 
3704 hidnplayr 758
        cmp     ebx, EWOULDBLOCK
759
        jne     .return
760
 
761
        test    edi, MSG_DONTWAIT
762
        jnz     .return_err
763
 
3737 hidnplayr 764
        test    [eax + SOCKET.state], SS_CANTRCVMORE
765
        jnz     .return_err
766
 
3704 hidnplayr 767
;        test    [eax + SOCKET.options], SO_NONBLOCK
768
;        jnz     .return_err
769
 
770
        call    SOCKET_block
771
        jmp     .loop
772
 
773
 
774
  .invalid:
775
        push    EINVAL
776
        pop     ebx
777
  .return_err:
778
        mov     eax, -1
779
  .return:
3673 hidnplayr 780
        mov     [esp+20], ebx
3565 hidnplayr 781
        mov     [esp+32], eax
782
        ret
3545 hidnplayr 783
 
3565 hidnplayr 784
 
3658 hidnplayr 785
 
3704 hidnplayr 786
 
787
 
3545 hidnplayr 788
align 4
789
SOCKET_receive_dgram:
3704 hidnplayr 790
 
3556 hidnplayr 791
        DEBUGF  DEBUG_NETWORK_VERBOSE, "SOCKET_receive: DGRAM\n"
3545 hidnplayr 792
 
3704 hidnplayr 793
        mov     ebx, esi                                        ; bufferlength
3545 hidnplayr 794
 
3704 hidnplayr 795
        get_from_queue (eax + SOCKET_QUEUE_LOCATION), SOCKET_QUEUE_SIZE, sizeof.socket_queue_entry, .wouldblock ; sets esi only on success.
3545 hidnplayr 796
        mov     ecx, [esi + socket_queue_entry.data_size]
3556 hidnplayr 797
        DEBUGF  DEBUG_NETWORK_VERBOSE, "SOCKET_receive: %u bytes data\n", ecx
3545 hidnplayr 798
 
3704 hidnplayr 799
        cmp     ecx, ebx                                        ; If data segment does not fit in applications buffer, abort
3545 hidnplayr 800
        ja      .too_small
801
 
3565 hidnplayr 802
        push    ecx
3545 hidnplayr 803
        push    [esi + socket_queue_entry.buf_ptr]              ; save the buffer addr so we can clear it later
804
        mov     esi, [esi + socket_queue_entry.data_ptr]
3556 hidnplayr 805
        DEBUGF  DEBUG_NETWORK_VERBOSE, "SOCKET_receive: Source buffer=%x real addr=%x\n", [esp], esi
3545 hidnplayr 806
 
3704 hidnplayr 807
; copy the data from kernel buffer to application buffer
808
        mov     edi, edx                                        ; bufferaddr
3545 hidnplayr 809
        shr     ecx, 1
810
        jnc     .nb
811
        movsb
812
  .nb:
813
        shr     ecx, 1
814
        jnc     .nw
815
        movsw
816
  .nw:
817
        test    ecx, ecx
818
        jz      .nd
3711 clevermous 819
        rep movsd
3545 hidnplayr 820
  .nd:
821
 
3861 hidnplayr 822
        call    NET_packet_free
3704 hidnplayr 823
        pop     eax                                             ; return number of bytes copied to application
824
        xor     ebx, ebx
3545 hidnplayr 825
        ret
826
 
827
  .too_small:
3565 hidnplayr 828
        mov     eax, -1
3704 hidnplayr 829
        push    EMSGSIZE
830
        pop     ebx
3565 hidnplayr 831
        ret
3545 hidnplayr 832
 
3658 hidnplayr 833
  .wouldblock:
3704 hidnplayr 834
        push    EWOULDBLOCK
835
        pop     ebx
3658 hidnplayr 836
        ret
3545 hidnplayr 837
 
3658 hidnplayr 838
 
3704 hidnplayr 839
 
3545 hidnplayr 840
align 4
841
SOCKET_receive_local:
842
 
843
        ; does this socket have a PID yet?
844
        cmp     [eax + SOCKET.PID], 0
845
        jne     @f
846
 
847
        ; Change PID to that of current process
848
        mov     ebx, [TASK_BASE]
849
        mov     ebx, [ebx + TASKDATA.pid]
850
        mov     [eax + SOCKET.PID], ebx
3704 hidnplayr 851
        mov     [eax + SOCKET.TID], ebx                         ; currently TID = PID in kolibrios :(
3545 hidnplayr 852
      @@:
853
 
854
        mov     [eax + SOCKET.rcv_proc], SOCKET_receive_stream
855
 
3704 hidnplayr 856
; ... continue to SOCKET_receive_stream
857
 
3545 hidnplayr 858
align 4
859
SOCKET_receive_stream:
860
 
3556 hidnplayr 861
        DEBUGF  DEBUG_NETWORK_VERBOSE, "SOCKET_receive: STREAM\n"
3545 hidnplayr 862
 
3704 hidnplayr 863
        cmp     [eax + STREAM_SOCKET.rcv + RING_BUFFER.size], 0
864
        je      .wouldblock
865
 
866
        test    edi, MSG_PEEK
867
        jnz     .peek
868
 
3545 hidnplayr 869
        mov     ecx, esi
870
        mov     edi, edx
871
        xor     edx, edx
872
 
873
        add     eax, STREAM_SOCKET.rcv
3704 hidnplayr 874
        call    SOCKET_ring_read                                ; copy data from kernel buffer to application buffer
875
        call    SOCKET_ring_free                                ; free read memory
3545 hidnplayr 876
 
3704 hidnplayr 877
        mov     eax, ecx                                        ; return number of bytes copied
878
        xor     ebx, ebx                                        ; errorcode = 0 (no error)
3545 hidnplayr 879
        ret
880
 
3704 hidnplayr 881
  .wouldblock:
882
        push    EWOULDBLOCK
883
        pop     ebx
884
        ret
885
 
3545 hidnplayr 886
  .peek:
3565 hidnplayr 887
        mov     eax, [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
3658 hidnplayr 1196
        jz      .nomem1
3545 hidnplayr 1197
        mov     [esp+32], edi   ; application's eax
1198
 
1199
        mov     [eax + SOCKET.Domain], AF_LOCAL
1200
        mov     [eax + SOCKET.Type], SOCK_STREAM
1201
        mov     [eax + SOCKET.Protocol], 0              ;;; CHECKME
1202
        mov     [eax + SOCKET.snd_proc], SOCKET_send_local
1203
        mov     [eax + SOCKET.rcv_proc], SOCKET_receive_local
1204
        mov     [eax + SOCKET.PID], 0
1205
        mov     ebx, eax
1206
 
1207
        call    SOCKET_alloc
3658 hidnplayr 1208
        jz      .nomem2
3673 hidnplayr 1209
        mov     [esp+20], edi   ; application's ebx
3545 hidnplayr 1210
 
1211
        mov     [eax + SOCKET.Domain], AF_LOCAL
1212
        mov     [eax + SOCKET.Type], SOCK_STREAM
1213
        mov     [eax + SOCKET.Protocol], 0              ;;; CHECKME
1214
        mov     [eax + SOCKET.snd_proc], SOCKET_send_local
1215
        mov     [eax + SOCKET.rcv_proc], SOCKET_receive_local
1216
        mov     [eax + SOCKET.PID], 0
1217
 
1218
        ; Link the two sockets to eachother
1219
        mov     [eax + SOCKET.device], ebx
1220
        mov     [ebx + SOCKET.device], eax
1221
 
1222
        lea     eax, [eax + STREAM_SOCKET.rcv]
1223
        call    SOCKET_ring_create
1224
 
1225
        lea     eax, [ebx + STREAM_SOCKET.rcv]
1226
        call    SOCKET_ring_create
1227
        pop     eax
1228
 
1229
        ret
1230
 
3658 hidnplayr 1231
  .nomem2:
3545 hidnplayr 1232
        mov     eax, ebx
1233
        call    SOCKET_free
3658 hidnplayr 1234
  .nomem1:
1235
        mov     dword[esp+32], -1
1236
        mov     dword[esp+28], ENOMEM
1237
        ret
3545 hidnplayr 1238
 
1239
 
1240
 
1241
;-----------------------------------------------------------------
1242
;
1243
; SOCKET_debug
1244
;
1245
;  Copies socket variables to application buffer
1246
;
1247
;  IN:  ecx = socket number
1248
;       edx = pointer to buffer
1249
;
1250
;  OUT: -1 on error
1251
;-----------------------------------------------------------------
1252
align 4
1253
SOCKET_debug:
1254
 
3556 hidnplayr 1255
        DEBUGF  DEBUG_NETWORK_VERBOSE, "SOCKET_debug\n"
3545 hidnplayr 1256
 
1257
        mov     edi, edx
1258
 
1259
        test    ecx, ecx
1260
        jz      .returnall
1261
 
1262
        call    SOCKET_num_to_ptr
3658 hidnplayr 1263
        jz      .invalid
3545 hidnplayr 1264
 
1265
        mov     esi, eax
1266
        mov     ecx, SOCKETBUFFSIZE/4
3711 clevermous 1267
        rep movsd
3545 hidnplayr 1268
 
3658 hidnplayr 1269
        mov     dword[esp+32], 0
3545 hidnplayr 1270
        ret
1271
 
1272
  .returnall:
1273
        mov     ebx, net_sockets
1274
  .next_socket:
1275
        mov     ebx, [ebx + SOCKET.NextPtr]
1276
        test    ebx, ebx
1277
        jz      .done
1278
        mov     eax, [ebx + SOCKET.Number]
1279
        stosd
1280
        jmp     .next_socket
1281
  .done:
1282
        xor     eax, eax
1283
        stosd
3658 hidnplayr 1284
        mov     dword[esp+32], eax
1285
        ret
3545 hidnplayr 1286
 
3658 hidnplayr 1287
  .invalid:
1288
        mov     dword[esp+32], -1
1289
        mov     dword[esp+28], EINVAL
3545 hidnplayr 1290
        ret
1291
 
1292
 
1293
;-----------------------------------------------------------------
1294
;
1295
; SOCKET_find_port
1296
;
1297
; Fills in the local port number for TCP and UDP sockets
1298
; This procedure always works because the number of sockets is
1299
; limited to a smaller number then the number of possible ports
1300
;
1301
;  IN:  eax = socket pointer
1302
;  OUT: /
1303
;
1304
;-----------------------------------------------------------------
1305
align 4
1306
SOCKET_find_port:
1307
 
3556 hidnplayr 1308
        DEBUGF  DEBUG_NETWORK_VERBOSE, "SOCKET_find_port\n"
3545 hidnplayr 1309
 
1310
        push    ebx esi ecx
1311
 
1312
        cmp     [eax + SOCKET.Protocol], IP_PROTO_UDP
1313
        je      .udp
1314
 
1315
        cmp     [eax + SOCKET.Protocol], IP_PROTO_TCP
1316
        je      .tcp
1317
 
1318
        pop     ecx esi ebx
1319
        ret
1320
 
1321
  .udp:
1322
        mov     bx, [last_UDP_port]
1323
        call    .findit
1324
        mov     [last_UDP_port], bx
1325
 
1326
        pop     ecx esi ebx
1327
        ret
1328
 
1329
  .tcp:
1330
        mov     bx, [last_TCP_port]
1331
        call    .findit
1332
        mov     [last_TCP_port], bx
1333
 
1334
        pop     ecx esi ebx
1335
        ret
1336
 
1337
 
1338
  .restart:
1339
        mov     bx, MIN_EPHEMERAL_PORT_N
1340
  .findit:
1341
        cmp     bx, MAX_EPHEMERAL_PORT_N
1342
        je      .restart
1343
 
1344
        add     bh, 1
1345
        adc     bl, 0
1346
 
1347
        call    SOCKET_check_port
1348
        jz      .findit
1349
        ret
1350
 
1351
 
1352
 
1353
;-----------------------------------------------------------------
1354
;
1355
; SOCKET_check_port (to be used with AF_INET only!)
1356
;
1357
; Checks if a local port number is unused
1358
; If the proposed port number is unused, it is filled in in the socket structure
1359
;
1360
;  IN:  eax = socket ptr (to find out if its a TCP/UDP socket)
1361
;        bx = proposed socket number (network byte order)
1362
;
1363
;  OUT:  ZF = set on error
1364
;
1365
;-----------------------------------------------------------------
1366
align 4
1367
SOCKET_check_port:
1368
 
3556 hidnplayr 1369
        DEBUGF  DEBUG_NETWORK_VERBOSE, "SOCKET_check_port: "
3545 hidnplayr 1370
 
3647 hidnplayr 1371
        pusha
1372
        mov     ecx, socket_mutex
1373
        call    mutex_lock
1374
        popa
1375
 
3545 hidnplayr 1376
        mov     ecx, [eax + SOCKET.Protocol]
1377
        mov     edx, [eax + IP_SOCKET.LocalIP]
1378
        mov     esi, net_sockets
1379
 
1380
  .next_socket:
1381
        mov     esi, [esi + SOCKET.NextPtr]
1382
        or      esi, esi
1383
        jz      .port_ok
1384
 
1385
        cmp     [esi + SOCKET.Protocol], ecx
1386
        jne     .next_socket
1387
 
1388
        cmp     [esi + IP_SOCKET.LocalIP], edx
1389
        jne     .next_socket
1390
 
1391
        cmp     [esi + UDP_SOCKET.LocalPort], bx
1392
        jne     .next_socket
1393
 
3647 hidnplayr 1394
        pusha
1395
        mov     ecx, socket_mutex
1396
        call    mutex_unlock
1397
        popa
1398
 
3556 hidnplayr 1399
        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 1400
        ret
1401
 
1402
  .port_ok:
3647 hidnplayr 1403
        pusha
1404
        mov     ecx, socket_mutex
1405
        call    mutex_unlock
1406
        popa
1407
 
3556 hidnplayr 1408
        DEBUGF  DEBUG_NETWORK_VERBOSE, "local port %x is free\n", bx         ; FIXME: find a way to print big endian values with debugf
3545 hidnplayr 1409
        mov     [eax + UDP_SOCKET.LocalPort], bx
1410
        or      bx, bx                                  ; clear the zero-flag
1411
        ret
1412
 
1413
 
1414
 
1415
;-----------------------------------------------------------------
1416
;
1417
; SOCKET_input
1418
;
1419
; Updates a (stateless) socket with received data
1420
;
1421
; Note: the mutex should already be set !
1422
;
1423
;  IN:  eax = socket ptr
1424
;       ecx = data size
1425
;       esi = ptr to data
1426
;       [esp] = ptr to buf
1427
;       [esp + 4] = buf size
1428
;
1429
;  OUT: /
1430
;
1431
;-----------------------------------------------------------------
1432
align 4
1433
SOCKET_input:
1434
 
3556 hidnplayr 1435
        DEBUGF  DEBUG_NETWORK_VERBOSE, "SOCKET_input: socket=%x, data=%x size=%u\n", eax, esi, ecx
3545 hidnplayr 1436
 
1437
        mov     [esp+4], ecx
1438
        push    esi
1439
        mov     esi, esp
1440
 
1441
        add_to_queue (eax + SOCKET_QUEUE_LOCATION), SOCKET_QUEUE_SIZE, sizeof.socket_queue_entry, SOCKET_input.full
1442
 
3556 hidnplayr 1443
        DEBUGF  DEBUG_NETWORK_VERBOSE, "SOCKET_input: success\n"
3545 hidnplayr 1444
        add     esp, sizeof.socket_queue_entry
1445
 
1446
        pusha
1447
        lea     ecx, [eax + SOCKET.mutex]
1448
        call    mutex_unlock
1449
        popa
1450
 
1451
        jmp     SOCKET_notify
1452
 
1453
  .full:
3556 hidnplayr 1454
        DEBUGF  DEBUG_NETWORK_VERBOSE, "SOCKET_input: socket %x is full!\n", eax
3545 hidnplayr 1455
 
1456
        pusha
1457
        lea     ecx, [eax + SOCKET.mutex]
1458
        call    mutex_unlock
1459
        popa
1460
 
3861 hidnplayr 1461
        call    NET_packet_free
3545 hidnplayr 1462
        add     esp, 8
1463
 
1464
        ret
1465
 
1466
 
1467
;--------------------------
1468
;
1469
; eax = ptr to ring struct (just a buffer of the right size)
1470
;
1471
align 4
1472
SOCKET_ring_create:
1473
 
1474
        push    esi
1475
        mov     esi, eax
1476
 
1477
        push    edx
1478
        stdcall create_ring_buffer, SOCKET_MAXDATA, PG_SW
1479
        pop     edx
1480
 
3556 hidnplayr 1481
        DEBUGF  DEBUG_NETWORK_VERBOSE, "SOCKET_ring_created: %x\n", eax
3545 hidnplayr 1482
 
1483
        pusha
1484
        lea     ecx, [esi + RING_BUFFER.mutex]
1485
        call    mutex_init
1486
        popa
1487
 
1488
        mov     [esi + RING_BUFFER.start_ptr], eax
1489
        mov     [esi + RING_BUFFER.write_ptr], eax
1490
        mov     [esi + RING_BUFFER.read_ptr], eax
1491
        mov     [esi + RING_BUFFER.size], 0
1492
        add     eax, SOCKET_MAXDATA
1493
        mov     [esi + RING_BUFFER.end_ptr], eax
1494
        mov     eax, esi
1495
        pop     esi
1496
 
1497
        ret
1498
 
1499
;-----------------------------------------------------------------
1500
;
1501
; SOCKET_ring_write
1502
;
1503
; Adds data to a stream socket, and updates write pointer and size
1504
;
1505
;  IN:  eax = ptr to ring struct
1506
;       ecx = data size
1507
;       esi = ptr to data
1508
;
1509
;  OUT: ecx = number of bytes stored
1510
;
1511
;-----------------------------------------------------------------
1512
align 4
1513
SOCKET_ring_write:
1514
 
3556 hidnplayr 1515
        DEBUGF  DEBUG_NETWORK_VERBOSE, "SOCKET_ring_write: ringbuff=%x ptr=%x size=%u\n", eax, esi, ecx
3545 hidnplayr 1516
 
1517
; lock mutex
1518
        pusha
1519
        lea     ecx, [eax + RING_BUFFER.mutex]
1520
        call    mutex_lock                                      ; TODO: check what registers this function actually destroys
1521
        popa
1522
 
1523
; calculate available size
1524
        mov     edi, SOCKET_MAXDATA
1525
        sub     edi, [eax + RING_BUFFER.size]                   ; available buffer size in edi
1526
        cmp     ecx, edi
1527
        jbe     .copy
1528
        mov     ecx, edi
1529
  .copy:
1530
        mov     edi, [eax + RING_BUFFER.write_ptr]
3556 hidnplayr 1531
        DEBUGF  DEBUG_NETWORK_VERBOSE, "SOCKET_ring_write: %u bytes from %x to %x\n", ecx, esi, edi
3545 hidnplayr 1532
 
1533
; update write ptr
1534
        push    edi
1535
        add     edi, ecx
1536
        cmp     edi, [eax + RING_BUFFER.end_ptr]
1537
        jb      @f
1538
        sub     edi, SOCKET_MAXDATA                             ; WRAP
1539
  @@:
1540
        mov     [eax + RING_BUFFER.write_ptr], edi
1541
        pop     edi
1542
 
1543
; update size
1544
        add     [eax + RING_BUFFER.size], ecx
1545
 
1546
; copy the data
1547
        push    ecx
1548
        shr     ecx, 1
1549
        jnc     .nb
1550
        movsb
1551
  .nb:
1552
        shr     ecx, 1
1553
        jnc     .nw
1554
        movsw
1555
  .nw:
1556
        test    ecx, ecx
1557
        jz      .nd
3711 clevermous 1558
        rep movsd
3545 hidnplayr 1559
  .nd:
1560
        pop     ecx
1561
 
1562
; unlock mutex
1563
        push    eax ecx
1564
        lea     ecx, [eax + RING_BUFFER.mutex]
1565
        call    mutex_unlock                                    ; TODO: check what registers this function actually destroys
1566
        pop     ecx eax
1567
 
1568
        ret
1569
 
1570
;-----------------------------------------------------------------
1571
;
1572
; SOCKET_ring_read
1573
;
1574
;  IN:  eax = ring struct ptr
1575
;       ecx = bytes to read
1576
;       edx = offset
1577
;       edi = ptr to buffer start
1578
;
1579
;  OUT: eax = unchanged
1580
;       ecx = number of bytes read (0 on error)
1581
;       edx = destroyed
1582
;       esi = destroyed
1583
;       edi = ptr to buffer end
1584
;
1585
;-----------------------------------------------------------------
1586
align 4
1587
SOCKET_ring_read:
1588
 
3556 hidnplayr 1589
        DEBUGF  DEBUG_NETWORK_VERBOSE, "SOCKET_ring_read: ringbuff=%x ptr=%x size=%u offset=%x\n", eax, edi, ecx, edx
3545 hidnplayr 1590
 
1591
        pusha
1592
        lea     ecx, [eax + RING_BUFFER.mutex]
1593
        call    mutex_lock                                      ; TODO: check what registers this function actually destroys
1594
        popa
1595
 
1596
        mov     esi, [eax + RING_BUFFER.read_ptr]
1597
        add     esi, edx                                        ; esi = start_ptr + offset
1598
 
1599
        neg     edx
1600
        add     edx, [eax + RING_BUFFER.size]                   ; edx = snd.size - offset
1601
        jle     .no_data_at_all
1602
 
1603
        pusha
1604
        lea     ecx, [eax + RING_BUFFER.mutex]
1605
        call    mutex_unlock                                    ; TODO: check what registers this function actually destroys
1606
        popa
1607
 
1608
        cmp     ecx, edx
1609
        ja      .less_data
1610
 
1611
  .copy:
3556 hidnplayr 1612
        DEBUGF  DEBUG_NETWORK_VERBOSE, "SOCKET_ring_read: %u bytes from %x to %x\n", ecx, esi, edi
3545 hidnplayr 1613
        push    ecx
1614
        shr     ecx, 1
1615
        jnc     .nb
1616
        movsb
1617
  .nb:
1618
        shr     ecx, 1
1619
        jnc     .nw
1620
        movsw
1621
  .nw:
1622
        test    ecx, ecx
1623
        jz      .nd
3711 clevermous 1624
        rep movsd
3545 hidnplayr 1625
  .nd:
1626
        pop     ecx
1627
        ret
1628
 
1629
  .no_data_at_all:
1630
        pusha
1631
        lea     ecx, [eax + RING_BUFFER.mutex]
1632
        call    mutex_unlock                                    ; TODO: check what registers this function actually destroys
1633
        popa
1634
 
3556 hidnplayr 1635
        DEBUGF  DEBUG_NETWORK_VERBOSE, "SOCKET_ring_read: no data at all!\n"
3545 hidnplayr 1636
        xor     ecx, ecx
1637
        ret
1638
 
1639
  .less_data:
1640
        mov     ecx, edx
1641
        jmp     .copy
1642
 
1643
 
1644
;-----------------------------------------------------------------
1645
;
1646
; SOCKET_ring_free
1647
;
1648
; Free's some bytes from the ringbuffer
1649
;
1650
;  IN:  eax = ptr to ring struct
1651
;       ecx = data size
1652
;
1653
;  OUT: ecx = number of bytes free-ed
1654
;
1655
;-----------------------------------------------------------------
1656
align 4
1657
SOCKET_ring_free:
1658
 
3556 hidnplayr 1659
        DEBUGF  DEBUG_NETWORK_VERBOSE, "SOCKET_ring_free: %u bytes from ring %x\n", ecx, eax
3545 hidnplayr 1660
 
1661
        push    eax ecx
1662
        lea     ecx, [eax + RING_BUFFER.mutex]
1663
        call    mutex_lock                                      ; TODO: check what registers this function actually destroys
1664
        pop     ecx eax
1665
 
1666
        sub     [eax + RING_BUFFER.size], ecx
1667
        jb      .error
1668
        add     [eax + RING_BUFFER.read_ptr], ecx
1669
 
1670
        mov     edx, [eax + RING_BUFFER.end_ptr]
1671
        cmp     [eax + RING_BUFFER.read_ptr], edx
1672
        jb      @f
1673
        sub     [eax + RING_BUFFER.read_ptr], SOCKET_MAXDATA
1674
       @@:
1675
 
1676
        push    eax ecx
1677
        lea     ecx, [eax + RING_BUFFER.mutex]                  ; TODO: check what registers this function actually destroys
1678
        call    mutex_unlock
1679
        pop     ecx eax
1680
 
1681
        ret
1682
 
1683
  .error:       ; we could free all available bytes, but that would be stupid, i guess..
3556 hidnplayr 1684
        DEBUGF  DEBUG_NETWORK_VERBOSE, "SOCKET_ring_free: buffer=%x error!\n", eax
3545 hidnplayr 1685
        add     [eax + RING_BUFFER.size], ecx
1686
 
1687
        push    eax
1688
        lea     ecx, [eax + RING_BUFFER.mutex]
1689
        call    mutex_unlock                                    ; TODO: check what registers this function actually destroys
1690
        pop     eax
1691
 
1692
        xor     ecx, ecx
1693
        ret
1694
 
1695
 
1696
;-----------------------------------------------------------------
1697
;
1698
; SOCKET_block
1699
;
1700
; Suspends the thread attached to a socket
1701
;
1702
;  IN:  eax = socket ptr
3674 hidnplayr 1703
;  OUT: eax = unchanged
3545 hidnplayr 1704
;
1705
;-----------------------------------------------------------------
1706
align 4
1707
SOCKET_block:
1708
 
3556 hidnplayr 1709
        DEBUGF  DEBUG_NETWORK_VERBOSE, "SOCKET_block: %x\n", eax
3545 hidnplayr 1710
 
1711
        pushf
3674 hidnplayr 1712
        push    eax
3545 hidnplayr 1713
        cli
1714
 
1715
        ; Set the 'socket is blocked' flag
1716
        or      [eax + SOCKET.state], SS_BLOCKED
1717
 
1718
        ; Suspend the thread
1719
        push    edx
1720
        mov     edx, [TASK_BASE]
1721
        mov     [edx + TASKDATA.state], 1               ; Suspended
1722
 
1723
        ; Remember the thread ID so we can wake it up again
1724
        mov     edx, [edx + TASKDATA.pid]
3556 hidnplayr 1725
        DEBUGF  DEBUG_NETWORK_VERBOSE, "SOCKET_block: suspending thread: %u\n", edx
3545 hidnplayr 1726
        mov     [eax + SOCKET.TID], edx
1727
        pop     edx
1728
 
1729
        call    change_task
3674 hidnplayr 1730
        pop     eax
3545 hidnplayr 1731
        popf
1732
 
3556 hidnplayr 1733
        DEBUGF  DEBUG_NETWORK_VERBOSE, "SOCKET_block: continueing\n"
3545 hidnplayr 1734
 
1735
        ret
1736
 
1737
 
1738
;-----------------------------------------------------------------
1739
;
1740
; SOCKET_notify
1741
;
1742
; notify's the owner of a socket that something happened
1743
;
1744
;  IN:  eax = socket ptr
3674 hidnplayr 1745
;  OUT: eax = unchanged
3545 hidnplayr 1746
;
1747
;-----------------------------------------------------------------
1748
align 4
1749
SOCKET_notify:
1750
 
3556 hidnplayr 1751
        DEBUGF  DEBUG_NETWORK_VERBOSE, "SOCKET_notify: %x\n", eax
3545 hidnplayr 1752
 
1753
        call    SOCKET_check
1754
        jz      .error
1755
 
1756
        test    [eax + SOCKET.state], SS_BLOCKED
1757
        jnz     .unblock
1758
 
3704 hidnplayr 1759
;        test    [eax + SOCKET.options], SO_NONBLOCK
1760
;        jz      .error
3545 hidnplayr 1761
 
1762
        push    eax ecx esi
1763
 
1764
; socket exists and is of non blocking type.
1765
; We'll try to flag an event to the thread
1766
 
1767
        mov     eax, [eax + SOCKET.TID]
1768
        test    eax, eax
1769
        jz      .done
1770
        mov     ecx, 1
1771
        mov     esi, TASK_DATA + TASKDATA.pid
1772
 
1773
  .next_pid:
1774
        cmp     [esi], eax
1775
        je      .found_pid
1776
        inc     ecx
1777
        add     esi, 0x20
1778
        cmp     ecx, [TASK_COUNT]
1779
        jbe     .next_pid
1780
; PID not found, TODO: close socket!
1781
        jmp     .done
1782
 
1783
  .found_pid:
1784
        shl     ecx, 8
1785
        or      [ecx + SLOT_BASE + APPDATA.event_mask], EVENT_NETWORK
1786
 
3817 hidnplayr 1787
        DEBUGF  DEBUG_NETWORK_VERBOSE, "SOCKET_notify: poking thread %u!\n", eax
3545 hidnplayr 1788
        jmp     .done
1789
 
1790
  .unblock:
1791
        push    eax ecx esi
1792
        ; Clear the 'socket is blocked' flag
1793
        and     [eax + SOCKET.state], not SS_BLOCKED
1794
 
1795
        ; Find the thread's TASK_DATA
1796
        mov     eax, [eax + SOCKET.TID]
1797
        test    eax, eax
1798
        jz      .error
1799
        xor     ecx, ecx
1800
        inc     ecx
1801
        mov     esi, TASK_DATA
1802
  .next:
1803
        cmp     [esi + TASKDATA.pid], eax
1804
        je      .found
1805
        inc     ecx
1806
        add     esi, 0x20
1807
        cmp     ecx, [TASK_COUNT]
1808
        jbe     .next
1809
        jmp     .error
1810
  .found:
1811
 
1812
        ; Run the thread
1813
        mov     [esi + TASKDATA.state], 0       ; Running
3556 hidnplayr 1814
        DEBUGF  DEBUG_NETWORK_VERBOSE, "SOCKET_notify: Unblocked socket!\n"
3545 hidnplayr 1815
 
1816
  .done:
1817
        pop     esi ecx eax
1818
 
1819
  .error:
1820
        ret
1821
 
1822
 
1823
;--------------------------------------------------------------------
1824
;
1825
; SOCKET_alloc
1826
;
1827
; Allocate memory for socket data and put new socket into the list
1828
; Newly created socket is initialized with calling PID and number and
1829
; put into beginning of list (which is a fastest way).
1830
;
1831
; IN:  /
1832
; OUT: eax = 0 on error, socket ptr otherwise
1833
;      edi = socket number
1834
;       ZF = cleared on error
1835
;
1836
;--------------------------------------------------------------------
1837
align 4
1838
SOCKET_alloc:
1839
 
1840
        push    ebx
1841
 
1842
        stdcall kernel_alloc, SOCKETBUFFSIZE
3556 hidnplayr 1843
        DEBUGF  DEBUG_NETWORK_VERBOSE, "SOCKET_alloc: ptr=%x\n", eax
3545 hidnplayr 1844
        or      eax, eax
1845
        jz      .exit
1846
 
1847
; zero-initialize allocated memory
1848
        push    eax
1849
        mov     edi, eax
1850
        mov     ecx, SOCKETBUFFSIZE / 4
1851
        xor     eax, eax
3711 clevermous 1852
        rep stosd
3545 hidnplayr 1853
        pop     eax
1854
 
1855
; set send-and receive procedures to return -1
3658 hidnplayr 1856
        mov     [eax + SOCKET.snd_proc], .not_yet
1857
        mov     [eax + SOCKET.rcv_proc], .not_yet
3545 hidnplayr 1858
 
3647 hidnplayr 1859
        pusha
1860
        mov     ecx, socket_mutex
1861
        call    mutex_lock
1862
        popa
1863
 
3545 hidnplayr 1864
; find first free socket number and use it
1865
        mov     edi, [last_socket_num]
1866
  .next_socket_number:
1867
        inc     edi
1868
        jz      .next_socket_number     ; avoid socket nr 0
1869
        cmp     edi, -1
1870
        je      .next_socket_number     ; avoid socket nr -1
1871
        mov     ebx, net_sockets
1872
  .next_socket:
1873
        mov     ebx, [ebx + SOCKET.NextPtr]
1874
        test    ebx, ebx
1875
        jz      .last_socket
1876
 
1877
        cmp     [ebx + SOCKET.Number], edi
1878
        jne     .next_socket
1879
        jmp     .next_socket_number
1880
 
1881
  .last_socket:
1882
        mov     [last_socket_num], edi
1883
        mov     [eax + SOCKET.Number], edi
3556 hidnplayr 1884
        DEBUGF  DEBUG_NETWORK_VERBOSE, "SOCKET_alloc: number=%u\n", edi
3545 hidnplayr 1885
 
1886
; Fill in PID
1887
        mov     ebx, [TASK_BASE]
1888
        mov     ebx, [ebx + TASKDATA.pid]
1889
        mov     [eax + SOCKET.PID], ebx
1890
        mov     [eax + SOCKET.TID], ebx         ; currently TID = PID in kolibrios :(
1891
 
1892
; init mutex
1893
        pusha
1894
        lea     ecx, [eax + SOCKET.mutex]
1895
        call    mutex_init
1896
        popa
1897
 
1898
; add socket to the list by re-arranging some pointers
1899
        mov     ebx, [net_sockets + SOCKET.NextPtr]
1900
 
1901
        mov     [eax + SOCKET.PrevPtr], net_sockets
1902
        mov     [eax + SOCKET.NextPtr], ebx
1903
 
1904
        test    ebx, ebx
1905
        jz      @f
1906
 
1907
        pusha
1908
        lea     ecx, [ebx + SOCKET.mutex]
1909
        call    mutex_lock
1910
        popa
1911
 
1912
        mov     [ebx + SOCKET.PrevPtr], eax
1913
 
1914
        pusha
1915
        lea     ecx, [ebx + SOCKET.mutex]
1916
        call    mutex_unlock
1917
        popa
1918
       @@:
1919
 
1920
        mov     [net_sockets + SOCKET.NextPtr], eax
1921
        or      eax, eax                ; used to clear zero flag
3647 hidnplayr 1922
 
1923
        pusha
1924
        mov     ecx, socket_mutex
1925
        call    mutex_unlock
1926
        popa
1927
 
3545 hidnplayr 1928
  .exit:
1929
        pop     ebx
1930
 
1931
        ret
1932
 
3658 hidnplayr 1933
  .not_yet:
3673 hidnplayr 1934
        mov     dword[esp+20], ENOTCONN
3658 hidnplayr 1935
        mov     dword[esp+32], -1
1936
        ret
3545 hidnplayr 1937
 
3658 hidnplayr 1938
 
3545 hidnplayr 1939
;----------------------------------------------------
1940
;
1941
; SOCKET_free
1942
;
1943
; Free socket data memory and remove socket from the list
3884 hidnplayr 1944
; Caller should lock and unlock socket_mutex
3545 hidnplayr 1945
;
1946
; IN:  eax = socket ptr
1947
; OUT: /
1948
;
1949
;----------------------------------------------------
1950
align 4
1951
SOCKET_free:
1952
 
3556 hidnplayr 1953
        DEBUGF  DEBUG_NETWORK_VERBOSE, "SOCKET_free: %x\n", eax
3545 hidnplayr 1954
 
1955
        call    SOCKET_check
1956
        jz      .error
1957
 
1958
        push    ebx
1959
 
1960
        pusha
1961
        lea     ecx, [eax + SOCKET.mutex]
1962
        call    mutex_lock
1963
        popa
1964
 
1965
        cmp     [eax + SOCKET.Domain], AF_INET4
1966
        jnz     .no_tcp
1967
 
1968
        cmp     [eax + SOCKET.Protocol], IP_PROTO_TCP
1969
        jnz     .no_tcp
1970
 
1971
        mov     ebx, eax
1972
        stdcall kernel_free, [ebx + STREAM_SOCKET.rcv.start_ptr]
1973
        stdcall kernel_free, [ebx + STREAM_SOCKET.snd.start_ptr]
1974
        mov     eax, ebx
1975
  .no_tcp:
1976
 
3652 hidnplayr 1977
        DEBUGF  DEBUG_NETWORK_VERBOSE, "SOCKET_free: freeing socket %x\n", eax
3545 hidnplayr 1978
        push    eax                             ; this will be passed to kernel_free
1979
        mov     ebx, [eax + SOCKET.NextPtr]
1980
        mov     eax, [eax + SOCKET.PrevPtr]
1981
 
3556 hidnplayr 1982
        DEBUGF  DEBUG_NETWORK_VERBOSE, "SOCKET_free: linking socket %x to socket %x\n", eax, ebx
3545 hidnplayr 1983
 
1984
        test    eax, eax
1985
        jz      @f
1986
        mov     [eax + SOCKET.NextPtr], ebx
1987
       @@:
1988
 
1989
        test    ebx, ebx
1990
        jz      @f
1991
        mov     [ebx + SOCKET.PrevPtr], eax
1992
       @@:
1993
 
1994
        call    kernel_free
1995
        pop     ebx
1996
 
3652 hidnplayr 1997
        DEBUGF  DEBUG_NETWORK_VERBOSE, "SOCKET_free: success!\n"
1998
 
1999
  .error:
3545 hidnplayr 2000
        ret
2001
 
2002
;------------------------------------
2003
;
2004
; SOCKET_fork
2005
;
2006
; Create a child socket
2007
;
2008
; IN:  socket nr in ebx
2009
; OUT: child socket nr in eax
2010
;
2011
;-----------------------------------
2012
align 4
2013
SOCKET_fork:
2014
 
3556 hidnplayr 2015
        DEBUGF  DEBUG_NETWORK_VERBOSE, "SOCKET_fork: %x\n", ebx
3545 hidnplayr 2016
 
2017
; Exit if backlog queue is full
2018
        mov     eax, [ebx + SOCKET_QUEUE_LOCATION + queue.size]
2019
        cmp     ax, [ebx + SOCKET.backlog]
2020
        jae     .fail
2021
 
2022
; Allocate new socket
2023
        push    ebx
2024
        call    SOCKET_alloc
2025
        pop     ebx
2026
        jz      .fail
2027
 
2028
        push    eax
2029
        mov     esi, esp
2030
        add_to_queue (ebx + SOCKET_QUEUE_LOCATION), MAX_backlog, 4, .fail2
2031
        pop     eax
2032
 
2033
; Copy structure from current socket to new
3817 hidnplayr 2034
; We start at PID to preserve the socket num, 2 pointers and mutex
2035
; TID will be filled in later
3545 hidnplayr 2036
        lea     esi, [ebx + SOCKET.PID]
2037
        lea     edi, [eax + SOCKET.PID]
2038
        mov     ecx, (SOCKET_QUEUE_LOCATION - SOCKET.PID + 3)/4
3711 clevermous 2039
        rep movsd
3545 hidnplayr 2040
 
2041
        and     [eax + SOCKET.options], not SO_ACCEPTCON
2042
 
3817 hidnplayr 2043
; Notify owner of parent socket
2044
        push    eax
2045
        mov     eax, ebx
2046
        call    SOCKET_notify
2047
        pop     eax
2048
 
3545 hidnplayr 2049
        ret
2050
 
2051
  .fail2:
2052
        add     esp, 4+4+4
2053
  .fail:
3556 hidnplayr 2054
        DEBUGF  DEBUG_NETWORK_ERROR, "SOCKET_fork: failed\n"
3545 hidnplayr 2055
        xor     eax, eax
2056
        ret
2057
 
2058
 
2059
;---------------------------------------------------
2060
;
2061
; SOCKET_num_to_ptr
2062
;
2063
; Get socket structure address by its number
2064
;
2065
; IN:  ecx = socket number
2066
; OUT: eax = 0 on error, socket ptr otherwise
2067
;       ZF = set on error
2068
;
2069
;---------------------------------------------------
2070
align 4
2071
SOCKET_num_to_ptr:
2072
 
3556 hidnplayr 2073
        DEBUGF  DEBUG_NETWORK_VERBOSE, "SOCKET_num_to_ptr: num=%u ", ecx
3545 hidnplayr 2074
 
3647 hidnplayr 2075
        pusha
2076
        mov     ecx, socket_mutex
2077
        call    mutex_lock
2078
        popa
2079
 
3545 hidnplayr 2080
        mov     eax, net_sockets
2081
 
2082
  .next_socket:
2083
        mov     eax, [eax + SOCKET.NextPtr]
2084
        or      eax, eax
2085
        jz      .error
2086
        cmp     [eax + SOCKET.Number], ecx
2087
        jne     .next_socket
2088
 
2089
        test    eax, eax
2090
 
3647 hidnplayr 2091
        pusha
2092
        mov     ecx, socket_mutex
2093
        call    mutex_unlock
2094
        popa
2095
 
3556 hidnplayr 2096
        DEBUGF  DEBUG_NETWORK_VERBOSE, "ptr=%x\n", eax
3545 hidnplayr 2097
        ret
2098
 
2099
  .error:
3647 hidnplayr 2100
        pusha
2101
        mov     ecx, socket_mutex
2102
        call    mutex_unlock
2103
        popa
2104
 
3637 hidnplayr 2105
        DEBUGF  DEBUG_NETWORK_ERROR, "SOCKET_num_to_ptr: not found\n", eax
3545 hidnplayr 2106
        ret
2107
 
2108
 
2109
;---------------------------------------------------
2110
;
2111
; SOCKET_ptr_to_num
2112
;
2113
; Get socket number by its address
2114
;
2115
; IN:  eax = socket ptr
2116
; OUT: eax = 0 on error, socket num otherwise
2117
;       ZF = set on error
2118
;
2119
;---------------------------------------------------
2120
align 4
2121
SOCKET_ptr_to_num:
2122
 
3556 hidnplayr 2123
        DEBUGF  DEBUG_NETWORK_VERBOSE, "SOCKET_ptr_to_num: ptr=%x ", eax
3545 hidnplayr 2124
 
2125
        call    SOCKET_check
2126
        jz      .error
2127
 
2128
        mov     eax, [eax + SOCKET.Number]
2129
 
3556 hidnplayr 2130
        DEBUGF  DEBUG_NETWORK_VERBOSE, "num=%u\n", eax
3545 hidnplayr 2131
        ret
2132
 
2133
  .error:
3556 hidnplayr 2134
        DEBUGF  DEBUG_NETWORK_ERROR, "SOCKET_ptr_to_num: not found\n", eax
3545 hidnplayr 2135
        ret
2136
 
2137
 
2138
;---------------------------------------------------
2139
;
2140
; SOCKET_check
2141
;
2142
; checks if the given value is really a socket ptr
2143
;
2144
; IN:  eax = socket ptr
2145
; OUT: eax = 0 on error, unchanged otherwise
2146
;       ZF = set on error
2147
;
2148
;---------------------------------------------------
2149
align 4
2150
SOCKET_check:
2151
 
3556 hidnplayr 2152
        DEBUGF  DEBUG_NETWORK_VERBOSE, "SOCKET_check: %x\n", eax
3545 hidnplayr 2153
 
2154
        push    ebx
2155
        mov     ebx, net_sockets
2156
 
2157
  .next_socket:
2158
        mov     ebx, [ebx + SOCKET.NextPtr]
2159
        or      ebx, ebx
2160
        jz      .done
2161
        cmp     ebx, eax
2162
        jnz     .next_socket
2163
 
2164
  .done:
2165
        mov     eax, ebx
2166
        test    eax, eax
2167
        pop     ebx
2168
 
2169
        ret
2170
 
2171
 
2172
 
2173
;---------------------------------------------------
2174
;
2175
; SOCKET_check_owner
2176
;
2177
; checks if the caller application owns the socket
2178
;
2179
; IN:  eax = socket ptr
2180
; OUT:  ZF = true/false
2181
;
2182
;---------------------------------------------------
2183
align 4
2184
SOCKET_check_owner:
2185
 
3556 hidnplayr 2186
        DEBUGF  DEBUG_NETWORK_VERBOSE, "SOCKET_check_owner: %x\n", eax
3545 hidnplayr 2187
 
2188
        push    ebx
2189
        mov     ebx, [TASK_BASE]
2190
        mov     ebx, [ebx + TASKDATA.pid]
2191
        cmp     [eax + SOCKET.PID], ebx
3711 clevermous 2192
        pop     ebx
3545 hidnplayr 2193
 
2194
        ret
2195
 
2196
 
2197
 
2198
 
2199
;------------------------------------------------------
2200
;
2201
; SOCKET_process_end
2202
;
2203
; Kernel calls this function when a certain process ends
2204
; This function will check if the process had any open sockets
2205
; And update them accordingly
2206
;
2207
; IN:  edx = pid
2208
; OUT: /
2209
;
2210
;------------------------------------------------------
2211
align 4
2212
SOCKET_process_end:
2213
 
3556 hidnplayr 2214
        DEBUGF  DEBUG_NETWORK_VERBOSE, "SOCKET_process_end: %x\n", edx
3545 hidnplayr 2215
 
3647 hidnplayr 2216
        pusha
2217
        mov     ecx, socket_mutex
2218
        call    mutex_lock
2219
        popa
2220
 
3545 hidnplayr 2221
        push    ebx
2222
        mov     ebx, net_sockets
2223
 
2224
  .next_socket:
2225
        mov     ebx, [ebx + SOCKET.NextPtr]
2226
  .next_socket_test:
2227
        test    ebx, ebx
2228
        jz      .done
2229
 
2230
        cmp     [ebx + SOCKET.PID], edx
2231
        jne     .next_socket
2232
 
3556 hidnplayr 2233
        DEBUGF  DEBUG_NETWORK_VERBOSE, "SOCKET_process_end: killing socket %x\n", ebx
3545 hidnplayr 2234
 
2235
        mov     [ebx + SOCKET.PID], 0
2236
        mov     eax, ebx
2237
        mov     ebx, [ebx + SOCKET.NextPtr]
3648 hidnplayr 2238
 
3545 hidnplayr 2239
        pusha
3652 hidnplayr 2240
        cmp     [eax + SOCKET.Domain], AF_INET4
2241
        jne     .free
2242
 
2243
        cmp     [eax + SOCKET.Protocol], IP_PROTO_TCP
2244
        jne     .free
2245
 
2246
        call    TCP_close
2247
        jmp     .closed
2248
 
2249
  .free:
2250
        call    SOCKET_free
2251
 
2252
  .closed:
3545 hidnplayr 2253
        popa
2254
        jmp     .next_socket_test
2255
 
2256
  .done:
2257
        pop     ebx
2258
 
3647 hidnplayr 2259
        pusha
2260
        mov     ecx, socket_mutex
2261
        call    mutex_unlock
2262
        popa
2263
 
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