Subversion Repositories Kolibri OS

Rev

Rev 1335 | Blame | Last modification | View Log | Download | RSS feed

  1. ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
  2. ;;                                                                 ;;
  3. ;; Copyright (C) KolibriOS team 2004-2009. All rights reserved.    ;;
  4. ;; Distributed under terms of the GNU General Public License       ;;
  5. ;;                                                                 ;;
  6. ;;  SOCKET.INC                                                     ;;
  7. ;;                                                                 ;;
  8. ;;    Written by hidnplayr@kolibrios.org                           ;;
  9. ;;    based on code by mike.dld                                    ;;
  10. ;;                                                                 ;;
  11. ;;          GNU GENERAL PUBLIC LICENSE                             ;;
  12. ;;             Version 2, June 1991                                ;;
  13. ;;                                                                 ;;
  14. ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
  15.  
  16. $Revision: 1473 $
  17.  
  18. struct  SOCKET_head
  19.          .NextPtr               dd ? ; pointer to next socket in list
  20.          .PrevPtr               dd ? ; pointer to previous socket in list
  21.          .Number                dd ? ; socket number (unique within single process)
  22.          .PID                   dd ? ; application process id
  23.          .Domain                dd ? ; INET/UNIX/..
  24.          .Type                  dd ? ; RAW/UDP/TCP/...
  25.          .Protocol              dd ? ; ICMP/IPv4/ARP/
  26.          .lock                  dd ? ; lock mutex
  27.          .errorcode             dd ?
  28.          .end:
  29. ends
  30.  
  31. struct  IPv4_SOCKET
  32.          .LocalIP               dd ?
  33.          .RemoteIP              dd ?
  34.          .SequenceNumber        dd ?
  35.  
  36.         ; todo: add options (for func 8 and 9)
  37.  
  38.          .end:
  39. ends
  40.  
  41. struct  TCP_SOCKET
  42.  
  43.          .LocalPort             dw ? ; In INET byte order
  44.          .RemotePort            dw ? ; In INET byte order
  45.  
  46.          .backlog               dw ? ; Backlog
  47.          .backlog_cur           dw ? ; current size of queue for un-accept-ed connections
  48.          .last_ack_number       dd ? ; used only to let application know that ACK has been received
  49.                                         ; todo: may be use SND_UNA instead
  50.                                         ; todo: may be use events which allow additional information instead
  51.                                         ; todo: may be count acknowledged bytes (at least it has obvious sense)
  52.          .OrigRemoteIP          dd ? ; original remote IP address (used to reset to LISTEN state)
  53.          .OrigRemotePort        dw ? ; original remote port (used to reset to LISTEN state)
  54.          .wndsizeTimer          dd ? ; window size timer
  55.  
  56.         ; Transmission control block
  57.          .state                 dd ? ; TCB state
  58.          .timer                 dd ? ; TCB timer (seconds)
  59.  
  60.          .ISS                   dd ? ; initial send sequence number
  61.          .IRS                   dd ? ; initial receive sequence number
  62.          .SND_UNA               dd ? ; sequence number of unack'ed sent Packets
  63.          .SND_NXT               dd ? ; next send sequence number to use
  64.          .SND_WND               dd ? ; send window
  65.          .RCV_NXT               dd ? ; next receive sequence number to use
  66.          .RCV_WND               dd ? ; receive window
  67.          .SEG_LEN               dd ? ; segment length
  68.          .SEG_WND               dd ? ; segment window
  69.  
  70.          .flags                 db ? ; packet flags
  71.  
  72.          .end:
  73. ends
  74.  
  75. struct  UDP_SOCKET
  76.  
  77.          .LocalPort             dw ? ; In INET byte order
  78.          .RemotePort            dw ? ; In INET byte order
  79.          .firstpacket           db ?
  80.  
  81.          .end:
  82. ends
  83.  
  84. struct  ICMP_SOCKET
  85.  
  86.         .Identifier             dw ? ;
  87.  
  88.         .end:
  89.  
  90. ends
  91.  
  92. struct  IPC_SOCKET
  93.  
  94.         .ConnectedTo            dd ? ; Socket number of other socket this one is connected to
  95.  
  96.         .end:
  97.  
  98. ends
  99.  
  100. struct  socket_queue_entry
  101.         .data_ptr       dd ?
  102.         .data_size      dd ?
  103.         .offset         dd ?
  104.         .size:
  105. ends
  106.  
  107. MAX_backlog             equ 20       ; backlog for stream sockets
  108. SOCKETBUFFSIZE          equ 4096     ; in bytes
  109. SOCKET_QUEUE_SIZE       equ 10       ; maximum number ofincoming packets queued for 1 socket
  110. SOCKET_QUEUE_LOCATION   equ 2048     ; the incoming packet queue for sockets is placed in the socket struct itself, at this location from start
  111.  
  112. uglobal
  113.         net_sockets     rd 2
  114.         last_UDP_port   dw ? ; These values give the number of the last used ephemeral port
  115.         last_TCP_port   dw ? ;
  116. endg
  117.  
  118.  
  119. ;-----------------------------------------------------------------
  120. ;
  121. ; SOCKET_init
  122. ;
  123. ;  -
  124. ;
  125. ;  IN:  /
  126. ;  OUT: /
  127. ;
  128. ;-----------------------------------------------------------------
  129. align 4
  130. socket_init:
  131.  
  132.         mov     [net_sockets], 0
  133.         mov     [net_sockets + 4], 0
  134.  
  135.         mov     [last_UDP_port], MIN_EPHEMERAL_PORT
  136.         mov     [last_TCP_port], MIN_EPHEMERAL_PORT
  137.  
  138.         ret
  139.  
  140.  
  141. ;-----------------------------------------------------------------
  142. ;
  143. ; Socket API (function 74)
  144. ;
  145. ;-----------------------------------------------------------------
  146. align 4
  147. sys_socket:
  148.         and     ebx, 0x000000FF ; should i remove this line ?
  149.         cmp     bl , 8          ; highest possible number
  150.         jg      s_error
  151.         lea     ebx, [.table + 4*ebx]
  152.         jmp     dword [ebx]
  153.  
  154. .table:
  155.         dd      socket_open     ; 0
  156.         dd      socket_close    ; 1
  157.         dd      socket_bind     ; 2
  158.         dd      socket_listen   ; 3
  159.         dd      socket_connect  ; 4
  160.         dd      socket_accept   ; 5
  161.         dd      socket_send     ; 6
  162.         dd      socket_recv     ; 7
  163.         dd      socket_get_opt  ; 8
  164. ;        dd      socket_set_opt  ; 9
  165.  
  166.  
  167. s_error:
  168.         mov     dword [esp+32],-1
  169.  
  170.         ret
  171.  
  172.  
  173. ;-----------------------------------------------------------------
  174. ;
  175. ; SOCKET_open
  176. ;
  177. ;
  178. ;  IN:  domain in ecx
  179. ;       type in edx
  180. ;       protocol in esi
  181. ;  OUT: eax is socket num, -1 on error
  182. ;
  183. ;-----------------------------------------------------------------
  184. align 4
  185. socket_open:
  186.  
  187.         DEBUGF  1,"socket_open: domain: %u, type: %u",ecx, edx
  188.  
  189.         call    net_socket_alloc
  190.         or      eax, eax
  191.         jz      s_error
  192.  
  193.         mov     [eax + SOCKET_head.Domain], ecx
  194.         mov     [eax + SOCKET_head.Type], edx
  195.         mov     [eax + SOCKET_head.Protocol], esi
  196.  
  197.         cmp     ecx, AF_INET4
  198.         je      .af_inet4
  199.  
  200.         jmp     .done
  201.  
  202.  
  203.   .af_inet4:
  204.  
  205.         cmp     edx, IP_PROTO_TCP
  206.         je      .tcp
  207.  
  208.         jmp     .done
  209.  
  210.   .tcp:
  211.  
  212.         mov     [eax + SOCKET_head.end + IPv4_SOCKET.end + TCP_SOCKET.state], TCB_CLOSED
  213.  
  214.         pseudo_random ebx
  215.         mov     [eax + SOCKET_head.end + IPv4_SOCKET.end + TCP_SOCKET.ISS], ebx
  216.         mov     [eax + SOCKET_head.end + IPv4_SOCKET.end + TCP_SOCKET.SND_NXT], ebx
  217.  
  218.   .done:
  219.         stdcall net_socket_addr_to_num, eax
  220.         DEBUGF  1,", socketnumber: %u\n", eax
  221.  
  222.         mov     [esp+32], eax
  223.  
  224.         ret
  225.  
  226.  
  227.  
  228. ;-----------------------------------------------------------------
  229. ;
  230. ; SOCKET_bind
  231. ;
  232. ;  IN:  socket number in ecx
  233. ;       pointer to sockaddr struct in edx
  234. ;       length of that struct in esi
  235. ;  OUT: 0 on success
  236. ;
  237. ;-----------------------------------------------------------------
  238. align 4
  239. socket_bind:
  240.  
  241.         DEBUGF  1,"Socket_bind: socknum: %u sockaddr: %x, length: %u, ",ecx,edx,esi
  242.  
  243.         stdcall net_socket_num_to_addr, ecx
  244.         cmp     eax, -1
  245.         jz      s_error
  246.  
  247.         cmp     esi, 2
  248.         jl      s_error
  249.  
  250.         cmp     word [edx], AF_INET4
  251.         je      .af_inet4
  252.  
  253.         cmp     word [edx], AF_UNIX
  254.         je      .af_unix
  255.  
  256.         jmp     s_error
  257.  
  258.   .af_unix:
  259.  
  260.         ; TODO: write code here
  261.  
  262.         mov     dword [esp+32],0
  263.         ret
  264.  
  265.   .af_inet4:
  266.  
  267.         cmp     esi, 6
  268.         jl      s_error
  269.  
  270.         mov     ecx, [eax + SOCKET_head.Type]
  271.  
  272.         mov     bx, word [edx + 2]
  273.         DEBUGF  1,"local port: %x ",bx
  274.         test    bx, bx
  275.         jz      .find_free
  276.  
  277.         call    socket_check_port
  278.         test    bx, bx
  279.         je      s_error
  280.         jmp     .got_port
  281.  
  282.     .find_free:
  283.  
  284.         call    socket_find_port
  285.         test    bx, bx
  286.         je      s_error
  287.  
  288.     .got_port:
  289.         DEBUGF  1,"using port: %x ",bx
  290.         mov     word [eax + SOCKET_head.end + IPv4_SOCKET.end + UDP_SOCKET.LocalPort], bx
  291.  
  292.         mov     ebx, dword [edx + 4]
  293.         mov     dword [eax + SOCKET_head.end + IPv4_SOCKET.LocalIP], ebx
  294.  
  295.         DEBUGF  1,"local ip: %u.%u.%u.%u\n",\
  296.         [eax + SOCKET_head.end + IPv4_SOCKET.LocalIP + 0]:1,[eax + SOCKET_head.end + IPv4_SOCKET.LocalIP + 1]:1,\
  297.         [eax + SOCKET_head.end + IPv4_SOCKET.LocalIP + 2]:1,[eax + SOCKET_head.end + IPv4_SOCKET.LocalIP + 3]:1
  298.  
  299.         mov     dword [esp+32],0
  300.         ret
  301.  
  302.  
  303.  
  304.  
  305. ;-----------------------------------------------------------------
  306. ;
  307. ; SOCKET_connect
  308. ;
  309. ;
  310. ;  IN:  socket number in ecx
  311. ;       pointer to sockaddr struct in edx
  312. ;       length of that struct in esi
  313. ;  OUT: 0 on success
  314. ;
  315. ;-----------------------------------------------------------------
  316. align 4
  317. socket_connect:
  318.  
  319.         DEBUGF  1,"Socket_connect: socknum: %u sockaddr: %x, length: %u,",ecx,edx,esi
  320.  
  321.         stdcall net_socket_num_to_addr, ecx
  322.         cmp     eax, -1
  323.         jz      s_error
  324.  
  325.         cmp     esi, 8
  326.         jl      s_error
  327.  
  328.         cmp     word [edx], AF_INET4
  329.         je      .af_inet4
  330.  
  331.         jmp     s_error
  332.  
  333.   .af_inet4:
  334.  
  335.         cmp     [eax + SOCKET_head.Type], IP_PROTO_UDP
  336.         je      .udp
  337.  
  338.         cmp     [eax + SOCKET_head.Type], IP_PROTO_TCP
  339.         je      .tcp
  340.  
  341.         jmp     s_error
  342.  
  343.   .udp:
  344.  
  345.         mov     bx , word [edx + 2]
  346.         mov     word [eax + SOCKET_head.end + IPv4_SOCKET.end + UDP_SOCKET.RemotePort], bx
  347.         mov     [eax + SOCKET_head.end + IPv4_SOCKET.end + UDP_SOCKET.firstpacket], 0
  348.         DEBUGF  1,"remote port: %x ",bx
  349.  
  350.         mov     ebx, dword [edx + 4]
  351.         mov     dword [eax + SOCKET_head.end + IPv4_SOCKET.RemoteIP], ebx
  352.         DEBUGF  1,"remote ip: %u.%u.%u.%u\n",[edx+4]:1,[edx+5]:1,[edx+6]:1,[edx+7]:1
  353.  
  354.         mov     dword [esp+32],0
  355.         ret
  356.  
  357.  
  358.   .tcp:
  359.         ; TODO: set sequence number to random value
  360.  
  361.         lea     ebx, [eax + SOCKET_head.lock]
  362.         call    wait_mutex
  363.  
  364.         ; fill in remote port and IP
  365.  
  366.         mov     [eax + SOCKET_head.end + IPv4_SOCKET.end + TCP_SOCKET.wndsizeTimer], 0     ; Reset the window timer.
  367.                                                                                            ; TODO: figure out WTF this is
  368.         mov     bx , word [edx + 2]
  369.         mov     [eax + SOCKET_head.end + IPv4_SOCKET.end + TCP_SOCKET.RemotePort], bx
  370.         DEBUGF  1,"remote port: %x ",bx
  371.  
  372.         mov     ebx, dword [edx + 4]
  373.         mov     [eax + SOCKET_head.end + IPv4_SOCKET.RemoteIP], ebx
  374.  
  375.         ; check if local port and IP is ok
  376.  
  377.         cmp     [eax + SOCKET_head.end + IPv4_SOCKET.LocalIP], 0
  378.         jne     @f
  379.         push    [IP_LIST]           ; device zero = default
  380.         pop     [eax + SOCKET_head.end + IPv4_SOCKET.LocalIP]
  381.        @@:
  382.  
  383.         cmp     [eax + SOCKET_head.end + IPv4_SOCKET.end + TCP_SOCKET.LocalPort], 0
  384.         jne     @f
  385.  
  386.         mov     ecx, [eax + SOCKET_head.Type]
  387.         call    socket_find_port
  388.         test    bx, bx
  389.         jz      s_error
  390.  
  391.         mov     [eax + SOCKET_head.end + IPv4_SOCKET.end + TCP_SOCKET.LocalPort], bx
  392.        @@:
  393.  
  394.  
  395.         mov     [eax + SOCKET_head.end + IPv4_SOCKET.end + TCP_SOCKET.state], TCB_SYN_SENT
  396.         ; now say hello to the remote tcp socket
  397.  
  398.         mov     bl, TH_SYN
  399.         xor     ecx, ecx
  400.         call    TCP_send
  401.  
  402.         mov     dword [esp+32],0
  403.         ret
  404.  
  405.  
  406. ;-----------------------------------------------------------------
  407. ;
  408. ; SOCKET_listen
  409. ;
  410. ;
  411. ;  IN:  socket number in ecx
  412. ;       backlog in edx
  413. ;  OUT: eax is socket num, -1 on error
  414. ;
  415. ;-----------------------------------------------------------------
  416. align 4
  417. socket_listen:
  418.  
  419.         DEBUGF  1,"Socket_listen: socknum: %u backlog: %u\n",ecx,edx
  420.  
  421.         stdcall net_socket_num_to_addr, ecx
  422.         cmp     eax, -1
  423.         jz      s_error
  424.  
  425.         cmp     word [eax + SOCKET_head.Domain], AF_INET4
  426.         jne     s_error
  427.  
  428.         cmp     [eax + SOCKET_head.Type], IP_PROTO_TCP
  429.         jne     s_error
  430.  
  431.         cmp     edx, MAX_backlog
  432.         jb      .ok
  433.         mov     dx , MAX_backlog
  434.   .ok:
  435.  
  436.         mov     [eax + SOCKET_head.end + IPv4_SOCKET.end + TCP_SOCKET.backlog], dx
  437.         mov     [eax + SOCKET_head.end + IPv4_SOCKET.end + TCP_SOCKET.state], TCB_LISTEN
  438.  
  439.         mov     dword [esp+32], 0
  440.         ret
  441.  
  442.  
  443. ;-----------------------------------------------------------------
  444. ;
  445. ; SOCKET_accept
  446. ;
  447. ;
  448. ;  IN:  socket number in ecx
  449. ;       addr in edx
  450. ;       addrlen in esi
  451. ;  OUT: eax is socket num, -1 on error
  452. ;
  453. ;-----------------------------------------------------------------
  454. align 4
  455. socket_accept:
  456.  
  457.         DEBUGF  1,"Socket_accept: socknum: %u sockaddr: %x, length: %u\n",ecx,edx,esi
  458.  
  459.         stdcall net_socket_num_to_addr, ecx
  460.         or      eax, eax
  461.         jz      s_error
  462.         mov     esi, eax
  463.  
  464.         cmp     word [esi + SOCKET_head.Domain], AF_INET4
  465.         je      .af_inet4
  466.  
  467.         jmp     s_error
  468.  
  469.   .af_inet4:
  470.  
  471.         cmp     [esi + SOCKET_head.Type], IP_PROTO_TCP
  472.         je      .tcp
  473.  
  474.         jmp     s_error
  475.  
  476.   .tcp:
  477.  
  478.         lea     ebx, [esi + SOCKET_head.lock]
  479.         call    wait_mutex
  480.         movzx   eax, [esi + SOCKET_head.end + IPv4_SOCKET.end + TCP_SOCKET.backlog_cur]
  481.         test    eax, eax
  482.         jz      .unlock_err
  483.         dec     [esi + SOCKET_head.end + IPv4_SOCKET.end + TCP_SOCKET.backlog_cur]
  484.         mov     eax, [eax + SOCKET_head.end + IPv4_SOCKET.end + TCP_SOCKET.end + (eax-1)*4]
  485.         mov     [esi + SOCKET_head.lock], 0
  486.         stdcall net_socket_addr_to_num, eax
  487.         mov     [esp+32], eax
  488.         ret
  489.   .unlock_err:
  490.         mov     [esi + SOCKET_head.lock], 0
  491.         jmp     s_error
  492.  
  493.  
  494. ;-----------------------------------------------------------------
  495. ;
  496. ; SOCKET_close
  497. ;
  498. ;
  499. ;  IN:  socket number in ecx
  500. ;  OUT: eax is socket num, -1 on error
  501. ;
  502. ;-----------------------------------------------------------------
  503. align 4
  504. socket_close:
  505.  
  506.         DEBUGF  1,"Socket_close: socknum: %u\n",ecx
  507.  
  508.         stdcall net_socket_num_to_addr, ecx
  509.         or      eax, eax
  510.         jz      s_error
  511.  
  512.         cmp     [eax + SOCKET_head.Domain], AF_INET4
  513.         jne     s_error
  514.  
  515.         cmp     [eax + SOCKET_head.Type], IP_PROTO_UDP
  516.         je      .udp
  517.  
  518.         cmp     [eax + SOCKET_head.Type], IP_PROTO_ICMP
  519.         je      .icmp
  520.  
  521.         cmp     [eax + SOCKET_head.Type], IP_PROTO_TCP
  522.         je      .tcp
  523.  
  524.         jmp     s_error
  525.  
  526.   .udp:
  527.  
  528.         stdcall net_socket_free, eax
  529.         mov     dword [esp+32],0
  530.         ret
  531.  
  532.  
  533.   .icmp:
  534.  
  535.  
  536.  
  537.         ret
  538.  
  539.   .tcp:
  540.         mov     dword [esp+32],0
  541.  
  542.         ; first, remove all resend entries for this socket
  543.  
  544.         call    TCP_remove_socket
  545.  
  546. ;        cmp     [eax + SOCKET_head.end + IPv4_SOCKET.end + TCP_SOCKET.state], TCB_LISTEN
  547. ;        je      .destroy_tcb
  548. ;        cmp     [eax + SOCKET_head.end + IPv4_SOCKET.end + TCP_SOCKET.state], TCB_SYN_SENT
  549. ;        je      .destroy_tcb
  550. ;        cmp     [eac + SOCKET_head.end + IPv4_SOCKET.end + TCP_SOCKET.state], TCB_CLOSED
  551. ;        je      .destroy_tcb
  552.         cmp     [eax + SOCKET_head.end + IPv4_SOCKET.end + TCP_SOCKET.state], TCB_SYN_RECEIVED
  553.         je      .fin_wait
  554.         cmp     [eax + SOCKET_head.end + IPv4_SOCKET.end + TCP_SOCKET.state], TCB_ESTABLISHED
  555.         je      .fin_wait
  556.         cmp     [eax + SOCKET_head.end + IPv4_SOCKET.end + TCP_SOCKET.state], TCB_CLOSE_WAIT
  557.         je      .last_ack
  558.  
  559.         stdcall net_socket_free, ebx
  560.  
  561.         ret
  562.  
  563.  
  564.   .last_ack:
  565.         mov     [eax + SOCKET_head.end + IPv4_SOCKET.end + TCP_SOCKET.state], TCB_LAST_ACK
  566.         jmp     .send_fin
  567.  
  568.   .fin_wait:
  569.         mov     [eax + SOCKET_head.end + IPv4_SOCKET.end + TCP_SOCKET.state], TCB_FIN_WAIT_1
  570.  
  571.   .send_fin:
  572.         mov     bl, TH_FIN + TH_ACK
  573.         xor     ecx, ecx
  574.         call    TCP_send
  575.  
  576.         ret
  577.  
  578.  
  579.  
  580.  
  581. ;-----------------------------------------------------------------
  582. ;
  583. ; SOCKET_receive
  584. ;
  585. ;
  586. ;  IN:  socket number in ecx
  587. ;       addr to buffer in edx
  588. ;       length of buffer in esi
  589. ;       flags in edi
  590. ;  OUT: eax is number of bytes copied, -1 on error
  591. ;
  592. ;-----------------------------------------------------------------
  593. align 4
  594. socket_recv:
  595.  
  596.         DEBUGF  1,"Socket_receive: socknum: %u bufaddr: %x, buflength: %u, flags: %x\n",ecx,edx,esi,edi
  597.         stdcall net_socket_num_to_addr, ecx                ; get real socket address
  598.         or      eax, eax
  599.         jz      s_error
  600.  
  601.         mov     ebx, esi
  602.  
  603.         DEBUGF  1,"Socket pointer: %x\n", eax
  604.  
  605.         get_from_queue (eax + SOCKET_QUEUE_LOCATION), SOCKET_QUEUE_SIZE, socket_queue_entry.size, s_error       ; destroys esi and ecx
  606.  
  607.         mov     edi, edx                                        ; addr to buffer
  608.         mov     ecx, [esi + socket_queue_entry.data_size]
  609.  
  610.         DEBUGF  1,"Got %u bytes of data\n", ecx
  611.  
  612.         cmp     ecx, ebx
  613.         jle     .large_enough
  614.         DEBUGF  1,"Buffer too small...\n"
  615.         jmp     s_error
  616.   .large_enough:
  617.  
  618.         push    [esi + socket_queue_entry.data_ptr]             ; save the buffer addr so we can clear it later
  619.         mov     esi, [esi + socket_queue_entry.offset]
  620.         add     esi, [esp]                                      ; calculate the real data offset
  621.         DEBUGF  1,"Source buffer: %x, real addr: %x\n", [esp], esi
  622.  
  623.         mov     dword[esp+32+4], ecx                            ; return number of bytes copied
  624.  
  625.         shr     ecx, 1
  626.         jnc     .nb
  627.         movsb
  628. .nb:    shr     ecx, 1
  629.         jnc     .nw
  630.         movsw
  631. .nw:    test    ecx, ecx
  632.         jz      .nd
  633.         rep     movsd
  634. .nd:
  635.  
  636.         call    kernel_free                                     ; todo: check if ALL applications had the chance to receive data
  637.  
  638.         ret
  639.  
  640.  
  641. ;-----------------------------------------------------------------
  642. ;
  643. ; SOCKET_send
  644. ;
  645. ;
  646. ;  IN:  socket number in ecx
  647. ;       pointer to data in edx
  648. ;       datalength in esi
  649. ;       flags in edi
  650. ;  OUT: -1 on error
  651. ;
  652. ;-----------------------------------------------------------------
  653. align 4
  654. socket_send:
  655.  
  656.         DEBUGF  1,"Socket_send: socknum: %u sockaddr: %x, length: %u, flags: %x, ",ecx,edx,esi,edi
  657.  
  658.         stdcall net_socket_num_to_addr, ecx                ; get real socket address
  659.         or      eax, eax
  660.         jz      s_error
  661.  
  662.         cmp     word [eax + SOCKET_head.Domain], AF_INET4
  663.         je      .af_inet4
  664.  
  665.         jmp     s_error
  666.  
  667.   .af_inet4:
  668.         DEBUGF  1,"Socket type:%u\n", [eax + SOCKET_head.Type]:4
  669.  
  670.         cmp     [eax + SOCKET_head.Type], IP_PROTO_TCP
  671.         je      .tcp
  672.  
  673.         cmp     [eax + SOCKET_head.Type], IP_PROTO_UDP
  674.         je      .udp
  675.  
  676.         cmp     [eax + SOCKET_head.Type], SOCK_RAW
  677.         je      .raw
  678.  
  679.         jmp     s_error
  680.  
  681.   .udp:
  682.  
  683.         DEBUGF  1,"type: UDP, "
  684.  
  685.         cmp     [eax + SOCKET_head.end + IPv4_SOCKET.end + UDP_SOCKET.LocalPort],0
  686.         jne     @f
  687.  
  688.         push    esi
  689.         mov     ecx, [eax + SOCKET_head.Type]
  690.         call    socket_find_port
  691.         test    bx, bx
  692.         pop     esi
  693.         je      s_error
  694.         mov     [eax + SOCKET_head.end + IPv4_SOCKET.end + UDP_SOCKET.LocalPort], bx
  695.  
  696.      @@:
  697.  
  698.         mov     ecx, esi
  699.         mov     esi, edx
  700.  
  701.         call    UDP_socket_send
  702.  
  703.         and     dword [esp+32], 0
  704.         ret
  705.  
  706.   .tcp:
  707.  
  708.         cmp     [eax + SOCKET_head.end + IPv4_SOCKET.end + TCP_SOCKET.LocalPort],0
  709.         jne     @f
  710.  
  711.         push    esi
  712.         mov     ecx, [eax + SOCKET_head.Type]
  713.         call    socket_find_port
  714.         test    bx, bx
  715.         pop     esi
  716.         je      s_error
  717.         mov     [eax + SOCKET_head.end + IPv4_SOCKET.end + TCP_SOCKET.LocalPort], bx
  718.  
  719.      @@:
  720.  
  721.         mov     ecx, esi
  722.         mov     esi, edx
  723.         mov     bl, TH_PUSH + TH_ACK
  724.  
  725.         call    TCP_send
  726.  
  727.         mov     [esp+32], eax
  728.         ret
  729.  
  730.   .raw:
  731.         cmp     [eax + SOCKET_head.Protocol], IP_PROTO_IP
  732.         je      .raw_ip
  733.  
  734.         cmp     [eax + SOCKET_head.Protocol], IP_PROTO_ICMP
  735.         je      .raw_icmp
  736.  
  737.         jmp     s_error
  738.  
  739.  
  740.   .raw_ip:
  741.  
  742.         ;;;;;;
  743.  
  744.         mov     [esp+32], eax
  745.         ret
  746.  
  747.  
  748.   .raw_icmp:
  749.  
  750. ;        sub     ecx, ICMP_Packet.Data
  751. ;        mov     esi, edx
  752. ;        push    ax
  753. ;        call    IPv4_get_frgmnt_num
  754. ;        mov     dx, ax
  755. ;        pop     ax
  756. ;        shl     edx, 16
  757. ;        mov     dh , [esi + ICMP_Packet.Type]
  758. ;        mov     dl , [esi + ICMP_Packet.Code]
  759. ;        mov     di , [esi + ICMP_Packet.Identifier]
  760. ;        mov     [eax + SOCKET.LocalPort], di            ; Set localport to the identifier number, so we can receive reply's
  761. ;        shl     edi, 16
  762. ;        mov     di , [esi + ICMP_Packet.SequenceNumber]
  763. ;        add     esi, ICMP_Packet.Data
  764. ;        mov     ebx, [eax + SOCKET.LocalIP]
  765. ;        mov     eax, [eax + SOCKET.RemoteIP]
  766. ;        call    ICMP_create_packet
  767.  
  768.         mov     [esp+32], eax
  769.         ret
  770.  
  771. ;-----------------------------------------------------------------
  772. ;
  773. ; SOCKET_get_options
  774. ;
  775. ;
  776. ;  IN:  socket number in ecx
  777. ;       edx points to the options:
  778. ;               dd      level, optname, optval, optlen
  779. ;  OUT: -1 on error
  780. ;
  781. ; At moment, uses only pseudo-optname -2 for get last_ack_number for TCP.
  782. ; TODO: find best way to notify that send()'ed data were acknowledged
  783. ; Also pseudo-optname -3 is valid and returns socket state, one of TCB_*.
  784. ;
  785. ;-----------------------------------------------------------------
  786. align 4
  787. socket_get_opt:
  788.  
  789.         cmp     dword [edx], IP_PROTO_TCP
  790.         jnz     .unknown
  791.         cmp     dword [edx+4], -2
  792.         jz      @f
  793.         cmp     dword [edx+4], -3
  794.         jnz     .unknown
  795. @@:
  796.         mov     eax, [edx+12]
  797.         test    eax, eax
  798.         jz      .fail
  799.         cmp     dword [eax], 4
  800.         mov     dword [eax], 4
  801.         jb      .fail
  802.         stdcall net_socket_num_to_addr, ecx
  803.         test    eax, eax
  804.         jz      .fail
  805.         ; todo: check that eax is really TCP socket
  806.         mov     ecx, [eax + SOCKET_head.end + IPv4_SOCKET.end + TCP_SOCKET.last_ack_number]
  807.         cmp     dword [edx+4], -2
  808.         jz      @f
  809.         mov     ecx, [eax + SOCKET_head.end + IPv4_SOCKET.end + TCP_SOCKET.state]
  810. @@:
  811.         mov     eax, [edx+8]
  812.         test    eax, eax
  813.         jz      @f
  814.         mov     [eax], ecx
  815. @@:
  816.         mov     dword [esp+32], 0
  817.         ret
  818. .fail:
  819. .unknown:
  820.         mov     dword [esp+32], -1
  821.         ret
  822.  
  823.  
  824. ;-----------------------------------------------------------------
  825. ;
  826. ; SOCKET_find_free_port (local port)
  827. ;
  828. ; works with INET byte order
  829. ;
  830. ;  IN:  type in ecx (TCP/UDP)
  831. ;  OUT: bx = 0 on error, portnumber otherwise
  832. ;
  833. ;-----------------------------------------------------------------
  834. align 4
  835. socket_find_port:
  836.  
  837.         DEBUGF  1,"Socket_find_free_port\n"
  838.  
  839.         cmp     ecx, IP_PROTO_UDP
  840.         je      .udp
  841.  
  842.         cmp     ecx, IP_PROTO_TCP
  843.         je      .tcp
  844.  
  845.   .udp:
  846.         mov     bx, [last_UDP_port]
  847.         je      .continue
  848.  
  849.   .tcp:
  850.         mov     bx, [last_TCP_port]
  851.  
  852.  
  853.   .continue:
  854.         inc     bx
  855.  
  856.   .check_only:
  857.         mov     esi, net_sockets
  858.  
  859.   .next_socket:
  860.         mov     esi, [esi + SOCKET_head.NextPtr]
  861.         or      esi, esi
  862.         jz      .port_ok
  863.  
  864.         cmp     [esi + SOCKET_head.Type], ecx
  865.         jne     .next_socket
  866.  
  867.         rol     bx, 8
  868.         cmp     [esi + SOCKET_head.end + IPv4_SOCKET.end + UDP_SOCKET.LocalPort], bx
  869.         rol     bx, 8                           ; this doesnt change the zero flag, does it ?
  870.         jne     .next_socket
  871.  
  872.         cmp     bx, MAX_EPHEMERAL_PORT
  873.         jle     .continue
  874.  
  875.         ; todo: WRAP!
  876. ;        mov     [last_UDP_port], MIN_EPHEMERAL_PORT
  877.   .exit:
  878.         xor     ebx, ebx
  879.  
  880.   .port_ok:
  881.         rol     bx, 8
  882.         ret
  883.  
  884.  
  885.  
  886. ;-----------------------------------------------------------------
  887. ;
  888. ; SOCKET_check_port (local port)
  889. ;
  890. ; works with INET byte order
  891. ;
  892. ;  IN:  type in ecx (TCP/UDP)
  893. ;       port to check in bx
  894. ;  OUT: bx = 0 on error, unchanged otherwise
  895. ;
  896. ;-----------------------------------------------------------------
  897. align 4
  898. socket_check_port:
  899.         mov     esi, net_sockets
  900.  
  901.   .next_socket:
  902.         mov     esi, [esi + SOCKET_head.NextPtr]
  903.         or      esi, esi
  904.         jz      .port_ok
  905.  
  906.         cmp     [esi + SOCKET_head.Type], ecx
  907.         jne     .next_socket
  908.  
  909.         cmp     [esi + SOCKET_head.end + IPv4_SOCKET.end + UDP_SOCKET.LocalPort], bx
  910.         jne     .next_socket
  911.  
  912.         xor     ebx, ebx
  913.  
  914.   .port_ok:
  915.         ret
  916.  
  917.  
  918.  
  919. ;-----------------------------------------------------------------
  920. ;
  921. ; SOCKET_internal_receiver
  922. ;
  923. ; Updates a socket with received data
  924. ;
  925. ; Note: the mutex must already be set !
  926. ;
  927. ;  IN:  eax = socket ptr
  928. ;       ecx = size
  929. ;       esi = pointer to buffer
  930. ;       edi = offset
  931. ;
  932. ;  OUT: xxx
  933. ;
  934. ;-----------------------------------------------------------------
  935. align 4
  936. socket_internal_receiver:
  937.  
  938.         DEBUGF  1,"Internal socket receiver: buffer %x, offset: %x size=%u socket: %x\n", esi, edi, ecx, eax
  939.  
  940.         push    edi     ; offset
  941.         push    ecx     ; size
  942.         push    esi     ; data_ptr
  943.         mov     esi, esp
  944.         add_to_queue (eax + SOCKET_QUEUE_LOCATION), SOCKET_QUEUE_SIZE, socket_queue_entry.size, notify_network_event.full
  945.         DEBUGF  1,"Queued packet successfully\n"
  946.         add     esp, socket_queue_entry.size
  947.  
  948.         mov     [eax + SOCKET_head.lock], 0
  949.  
  950. notify_network_event:
  951.         ; flag an event to the application
  952.         mov     edx, [eax + SOCKET_head.PID]                            ; get socket owner PID
  953.         mov     ecx, 1
  954.         mov     esi, TASK_DATA + TASKDATA.pid
  955.  
  956.        .next_pid:
  957.         cmp     [esi], edx
  958.         je      .found_pid
  959.         inc     ecx
  960.         add     esi, 0x20
  961.         cmp     ecx, [TASK_COUNT]
  962.         jbe     .next_pid
  963.         ret
  964.  
  965.        .found_pid:
  966.         shl     ecx, 8
  967.         or      [ecx + SLOT_BASE + APPDATA.event_mask], EVENT_NETWORK   ; stack event
  968.         mov     [check_idle_semaphore], 200
  969.         ret
  970.  
  971.   .full:
  972.         DEBUGF  2,"Socket %x is full!\n",eax
  973.         mov     [eax + SOCKET_head.lock], 0
  974.         call    kernel_free
  975.         add     esp, 8
  976.         ret
  977.  
  978.  
  979.  
  980. ; Allocate memory for socket data and put new socket into the list
  981. ; Newly created socket is initialized with calling PID and number and
  982. ; put into beginning of list (which is a fastest way).
  983. ;
  984. ; @return socket structure address in EAX
  985. ;
  986. proc net_socket_alloc stdcall uses ebx ecx edx edi
  987.         stdcall kernel_alloc, SOCKETBUFFSIZE
  988.         DEBUGF  1, "K : net_socket_alloc (0x%x)\n", eax
  989.         ; check if we can allocate needed amount of memory
  990.         or      eax, eax
  991.         jz      .exit
  992.  
  993.         ; zero-initialize allocated memory
  994.         push    eax
  995.         mov     edi, eax
  996.  
  997.         mov     ecx, SOCKETBUFFSIZE / 4
  998. ;        cld
  999.         xor     eax, eax
  1000.         rep     stosd
  1001.         pop     eax
  1002.  
  1003.         init_queue (eax + SOCKET_QUEUE_LOCATION)
  1004.  
  1005.         ; add socket to the list by changing pointers
  1006.         mov     ebx, net_sockets
  1007.         push    [ebx + SOCKET_head.NextPtr]
  1008.         mov     [ebx + SOCKET_head.NextPtr], eax
  1009.         mov     [eax + SOCKET_head.PrevPtr], ebx
  1010.         pop     ebx
  1011.         mov     [eax + SOCKET_head.NextPtr], ebx
  1012.         or      ebx, ebx
  1013.         jz      @f
  1014.         mov     [ebx + SOCKET_head.PrevPtr], eax
  1015.  
  1016.     @@: ; set socket owner PID to the one of calling process
  1017.         mov     ebx, [TASK_BASE]
  1018.         mov     ebx, [ebx + TASKDATA.pid]
  1019.         mov     [eax + SOCKET_head.PID], ebx
  1020.  
  1021.         ; find first free socket number and use it
  1022.         ;mov     edx, ebx
  1023.         mov     ebx, net_sockets
  1024.         xor     ecx, ecx
  1025.   .next_socket_number:
  1026.         inc     ecx
  1027.   .next_socket:
  1028.         mov     ebx, [ebx + SOCKET_head.NextPtr]
  1029.         or      ebx, ebx
  1030.         jz      .last_socket_number
  1031.         cmp     [ebx + SOCKET_head.Number], ecx
  1032.         jne     .next_socket
  1033.         ;cmp     [ebx + SOCKET.PID], edx
  1034.         ;jne     .next_socket
  1035.         mov     ebx, net_sockets
  1036.         jmp     .next_socket_number
  1037.  
  1038.   .last_socket_number:
  1039.         mov     [eax + SOCKET_head.Number], ecx
  1040.  
  1041.   .exit:
  1042.         ret
  1043. endp
  1044.  
  1045. ; Free socket data memory and pop socket off the list
  1046. ;
  1047. ; @param sockAddr is a socket structure address
  1048. ;
  1049. proc net_socket_free stdcall uses ebx ecx edx, sockAddr:DWORD
  1050.         mov     eax, [sockAddr]
  1051.         DEBUGF  1, "K : net_socket_free (0x%x)\n", eax
  1052.         ; check if we got something similar to socket structure address
  1053.         or      eax, eax
  1054.         jz      .error
  1055.  
  1056.         ; make sure sockAddr is one of the socket addresses in the list
  1057.         mov     ebx, net_sockets
  1058.         ;mov     ecx, [TASK_BASE]
  1059.         ;mov     ecx, [ecx + TASKDATA.pid]
  1060.   .next_socket:
  1061.         mov     ebx, [ebx + SOCKET_head.NextPtr]
  1062.         or      ebx, ebx
  1063.         jz      .error
  1064.         cmp     ebx, eax
  1065.         jne     .next_socket
  1066.         ;cmp     [ebx + SOCKET.PID], ecx
  1067.         ;jne     .next_socket
  1068.  
  1069.         ; okay, we found the correct one
  1070.         ; remove it from the list first, changing pointers
  1071.         mov     ebx, [eax + SOCKET_head.NextPtr]
  1072.         mov     eax, [eax + SOCKET_head.PrevPtr]
  1073.         mov     [eax + SOCKET_head.NextPtr], ebx
  1074.         or      ebx, ebx
  1075.         jz      @f
  1076.         mov     [ebx + SOCKET_head.PrevPtr], eax
  1077.  
  1078.         lea     ebx, [eax + SOCKET_head.lock]
  1079.         call    wait_mutex
  1080.  
  1081.     @@: ; and finally free the memory structure used
  1082.         stdcall kernel_free, [sockAddr]
  1083.         ret
  1084.  
  1085.   .error:
  1086.         DEBUGF  1, "K :   failed\n"
  1087.         ret
  1088. endp
  1089.  
  1090. ; Get socket structure address by its number
  1091. ; Scan through sockets list to find the socket with specified number.
  1092. ; This proc uses SOCKET.PID indirectly to check if socket is owned by
  1093. ; calling process.
  1094. ;
  1095. ; @param sockNum is a socket number
  1096. ; @return socket structure address or 0 (not found) in EAX
  1097. ;
  1098. proc net_socket_num_to_addr stdcall uses ebx ecx, sockNum:DWORD
  1099.         mov     eax, [sockNum]
  1100.         ; check if we got something similar to socket number
  1101.         or      eax, eax
  1102.         jz      .error
  1103.  
  1104.         ; scan through sockets list
  1105.         mov     ebx, net_sockets
  1106.         ;mov     ecx, [TASK_BASE]
  1107.         ;mov     ecx, [ecx + TASKDATA.pid]
  1108.   .next_socket:
  1109.         mov     ebx, [ebx + SOCKET_head.NextPtr]
  1110.         or      ebx, ebx
  1111.         jz      .error
  1112.         cmp     [ebx + SOCKET_head.Number], eax
  1113.         jne     .next_socket
  1114.         ;cmp     [ebx + SOCKET.PID], ecx
  1115.         ;jne     .next_socket
  1116.  
  1117.         ; okay, we found the correct one
  1118.         mov     eax, ebx
  1119.         ret
  1120.  
  1121.   .error:
  1122.         xor     eax, eax
  1123.         ret
  1124. endp
  1125.  
  1126. ; Get socket number by its structure address
  1127. ; Scan through sockets list to find the socket with specified address.
  1128. ; This proc uses SOCKET.PID indirectly to check if socket is owned by
  1129. ; calling process.
  1130. ;
  1131. ; @param sockAddr is a socket structure address
  1132. ; @return socket number (SOCKET.Number) or 0 (not found) in EAX
  1133. ;
  1134. proc net_socket_addr_to_num stdcall uses ebx ecx, sockAddr:DWORD
  1135.         mov     eax, [sockAddr]
  1136.         ; check if we got something similar to socket structure address
  1137.         or      eax, eax
  1138.         jz      .error
  1139.  
  1140.         ; scan through sockets list
  1141.         mov     ebx, net_sockets
  1142.         ;mov     ecx, [TASK_BASE]
  1143.         ;mov     ecx, [ecx + TASKDATA.pid]
  1144.   .next_socket:
  1145.         mov     ebx, [ebx + SOCKET_head.NextPtr]
  1146.         or      ebx, ebx
  1147.         jz      .error
  1148.         cmp     ebx, eax
  1149.         jne     .next_socket
  1150.         ;cmp     [ebx + SOCKET.PID], ecx
  1151.         ;jne     .next_socket
  1152.  
  1153.         ; okay, we found the correct one
  1154.         mov     eax, [ebx + SOCKET_head.Number]
  1155.         ret
  1156.  
  1157.   .error:
  1158.         xor     eax, eax
  1159.         ret
  1160. endp
  1161.