Subversion Repositories Kolibri OS

Rev

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