Subversion Repositories Kolibri OS

Rev

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

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