Subversion Repositories Kolibri OS

Rev

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