Subversion Repositories Kolibri OS

Rev

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

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