Subversion Repositories Kolibri OS

Rev

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