Subversion Repositories Kolibri OS

Rev

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

  1. ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
  2. ;;                                                              ;;
  3. ;; Copyright (C) KolibriOS team 2004-2008. All rights reserved. ;;
  4. ;; Distributed under terms of the GNU General Public License    ;;
  5. ;;                                                              ;;
  6. ;;  SOCKET.INC                                                  ;;
  7. ;;                                                              ;;
  8. ;;  Sockets constants, structures and functions                 ;;
  9. ;;                                                              ;;
  10. ;;  This file contains the following:                           ;;
  11. ;;    is_localport_unused                                       ;;
  12. ;;    get_free_socket                                           ;;
  13. ;;    socket_open                                               ;;
  14. ;;    socket_open_tcp                                           ;;
  15. ;;    socket_close                                              ;;
  16. ;;    socket_close_tcp                                          ;;
  17. ;;    socket_poll                                               ;;
  18. ;;    socket_status                                             ;;
  19. ;;    socket_read                                               ;;
  20. ;;    socket_write                                              ;;
  21. ;;    socket_write_tcp                                          ;;
  22. ;;                                                              ;;
  23. ;;                                                              ;;
  24. ;;  Changes history:                                            ;;
  25. ;;   22.09.2003 - [Mike Hibbett] : mikeh@oceanfree.net          ;;
  26. ;;   11.11.2006 - [Johnny_B] and [smb]                          ;;
  27. ;;                                                              ;;
  28. ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
  29.  
  30. $Revision: 1019 $
  31.  
  32. ; socket data structure
  33. struct SOCKET
  34.   .PrevPtr        dd ? ; pointer to previous socket in list
  35.   .NextPtr        dd ? ; pointer to next socket in list
  36.   .Number         dd ? ; socket number (unique within single process)
  37.   .PID            dd ? ; application process id
  38.   .LocalIP        dd ? ; local IP address
  39.   .LocalPort      dw ? ; local port
  40.   .RemoteIP       dd ? ; remote IP address
  41.   .RemotePort     dw ? ; remote port
  42.   .OrigRemoteIP   dd ? ; original remote IP address (used to reset to LISTEN state)
  43.   .OrigRemotePort dw ? ; original remote port (used to reset to LISTEN state)
  44.   .rxDataCount    dd ? ; rx data count
  45.   .TCBState       dd ? ; TCB state
  46.   .TCBTimer       dd ? ; TCB timer (seconds)
  47.   .ISS            dd ? ; initial send sequence
  48.   .IRS            dd ? ; initial receive sequence
  49.   .SND_UNA        dd ? ; sequence number of unack'ed sent packets
  50.   .SND_NXT        dd ? ; bext send sequence number to use
  51.   .SND_WND        dd ? ; send window
  52.   .RCV_NXT        dd ? ; next receive sequence number to use
  53.   .RCV_WND        dd ? ; receive window
  54.   .SEG_LEN        dd ? ; segment length
  55.   .SEG_WND        dd ? ; segment window
  56.   .wndsizeTimer   dd ? ; window size timer
  57.   .lock           dd ? ; lock mutex
  58.   .rxData         dd ? ; receive data buffer here
  59. ends
  60.  
  61. ; TCP opening modes
  62. SOCKET_PASSIVE = 0
  63. SOCKET_ACTIVE  = 1
  64.  
  65. ; socket types
  66. SOCK_STREAM = 1
  67. SOCK_DGRAM  = 2
  68.  
  69. ;; Allocate memory for socket data and put new socket into the list
  70. ; Newly created socket is initialized with calling PID and number and
  71. ; put into beginning of list (which is a fastest way).
  72. ;
  73. ; @return socket structure address in EAX
  74. ;;
  75. proc net_socket_alloc stdcall uses ebx ecx edx edi
  76.         stdcall kernel_alloc, SOCKETBUFFSIZE
  77.         DEBUGF  1, "K : net_socket_alloc (0x%x)\n", eax
  78.         ; check if we can allocate needed amount of memory
  79.         or      eax, eax
  80.         jz      .exit
  81.  
  82.         ; zero-initialize allocated memory
  83.         push    eax
  84.         mov     edi, eax
  85.         mov     ecx, SOCKETBUFFSIZE / 4
  86.         cld
  87.         xor     eax, eax
  88.         rep     stosd
  89.         pop     eax
  90.  
  91.         ; add socket to the list by changing pointers
  92.         mov     ebx, net_sockets
  93.         push    [ebx + SOCKET.NextPtr]
  94.         mov     [ebx + SOCKET.NextPtr], eax
  95.         mov     [eax + SOCKET.PrevPtr], ebx
  96.         pop     ebx
  97.         mov     [eax + SOCKET.NextPtr], ebx
  98.         or      ebx, ebx
  99.         jz      @f
  100.         mov     [ebx + SOCKET.PrevPtr], eax
  101.  
  102.     @@: ; set socket owner PID to the one of calling process
  103.         mov     ebx, [TASK_BASE]
  104.         mov     ebx, [ebx + TASKDATA.pid]
  105.         mov     [eax + SOCKET.PID], ebx
  106.  
  107.         ; find first free socket number and use it
  108.         ;mov     edx, ebx
  109.         mov     ebx, net_sockets
  110.         xor     ecx, ecx
  111.   .next_socket_number:
  112.         inc     ecx
  113.   .next_socket:
  114.         mov     ebx, [ebx + SOCKET.NextPtr]
  115.         or      ebx, ebx
  116.         jz      .last_socket_number
  117.         cmp     [ebx + SOCKET.Number], ecx
  118.         jne     .next_socket
  119.         ;cmp     [ebx + SOCKET.PID], edx
  120.         ;jne     .next_socket
  121.         mov     ebx, net_sockets
  122.         jmp     .next_socket_number
  123.  
  124.   .last_socket_number:
  125.         mov     [eax + SOCKET.Number], ecx
  126.  
  127.   .exit:
  128.         ret
  129. endp
  130.  
  131. ;; Free socket data memory and pop socket off the list
  132. ;
  133. ; @param sockAddr is a socket structure address
  134. ;;
  135. proc net_socket_free stdcall uses ebx ecx edx, sockAddr:DWORD
  136.         mov     eax, [sockAddr]
  137.         DEBUGF  1, "K : net_socket_free (0x%x)\n", eax
  138.         ; check if we got something similar to socket structure address
  139.         or      eax, eax
  140.         jz      .error
  141.  
  142.         ; make sure sockAddr is one of the socket addresses in the list
  143.         mov     ebx, net_sockets
  144.         ;mov     ecx, [TASK_BASE]
  145.         ;mov     ecx, [ecx + TASKDATA.pid]
  146.   .next_socket:
  147.         mov     ebx, [ebx + SOCKET.NextPtr]
  148.         or      ebx, ebx
  149.         jz      .error
  150.         cmp     ebx, eax
  151.         jne     .next_socket
  152.         ;cmp     [ebx + SOCKET.PID], ecx
  153.         ;jne     .next_socket
  154.  
  155.         ; okay, we found the correct one
  156.         ; remove it from the list first, changing pointers
  157.         mov     ebx, [eax + SOCKET.NextPtr]
  158.         mov     eax, [eax + SOCKET.PrevPtr]
  159.         mov     [eax + SOCKET.NextPtr], ebx
  160.         or      ebx, ebx
  161.         jz      @f
  162.         mov     [ebx + SOCKET.PrevPtr], eax
  163.  
  164.     @@: ; and finally free the memory structure used
  165.         stdcall kernel_free, [sockAddr]
  166.         ret
  167.  
  168.   .error:
  169.         DEBUGF  1, "K :   failed\n"
  170.         ret
  171. endp
  172.  
  173. ;; Get socket structure address by its number
  174. ; Scan through sockets list to find the socket with specified number.
  175. ; This proc uses SOCKET.PID indirectly to check if socket is owned by
  176. ; calling process.
  177. ;
  178. ; @param sockNum is a socket number
  179. ; @return socket structure address or 0 (not found) in EAX
  180. ;;
  181. proc net_socket_num_to_addr stdcall uses ebx ecx, sockNum:DWORD
  182.         mov     eax, [sockNum]
  183.         ; check if we got something similar to socket number
  184.         or      eax, eax
  185.         jz      .error
  186.  
  187.         ; scan through sockets list
  188.         mov     ebx, net_sockets
  189.         ;mov     ecx, [TASK_BASE]
  190.         ;mov     ecx, [ecx + TASKDATA.pid]
  191.   .next_socket:
  192.         mov     ebx, [ebx + SOCKET.NextPtr]
  193.         or      ebx, ebx
  194.         jz      .error
  195.         cmp     [ebx + SOCKET.Number], eax
  196.         jne     .next_socket
  197.         ;cmp     [ebx + SOCKET.PID], ecx
  198.         ;jne     .next_socket
  199.  
  200.         ; okay, we found the correct one
  201.         mov     eax, ebx
  202.         ret
  203.  
  204.   .error:
  205.         xor     eax, eax
  206.         ret
  207. endp
  208.  
  209. ;; Get socket number by its structure address
  210. ; Scan through sockets list to find the socket with specified address.
  211. ; This proc uses SOCKET.PID indirectly to check if socket is owned by
  212. ; calling process.
  213. ;
  214. ; @param sockAddr is a socket structure address
  215. ; @return socket number (SOCKET.Number) or 0 (not found) in EAX
  216. ;;
  217. proc net_socket_addr_to_num stdcall uses ebx ecx, sockAddr:DWORD
  218.         mov     eax, [sockAddr]
  219.         ; check if we got something similar to socket structure address
  220.         or      eax, eax
  221.         jz      .error
  222.  
  223.         ; scan through sockets list
  224.         mov     ebx, net_sockets
  225.         ;mov     ecx, [TASK_BASE]
  226.         ;mov     ecx, [ecx + TASKDATA.pid]
  227.   .next_socket:
  228.         mov     ebx, [ebx + SOCKET.NextPtr]
  229.         or      ebx, ebx
  230.         jz      .error
  231.         cmp     ebx, eax
  232.         jne     .next_socket
  233.         ;cmp     [ebx + SOCKET.PID], ecx
  234.         ;jne     .next_socket
  235.  
  236.         ; okay, we found the correct one
  237.         mov     eax, [ebx + SOCKET.Number]
  238.         ret
  239.  
  240.   .error:
  241.         xor     eax, eax
  242.         ret
  243. endp
  244.  
  245. ;; [53.9] Check if local port is used by any socket in the system.
  246. ; Scan through sockets list, checking SOCKET.LocalPort.
  247. ; Useful when you want a to generate a unique local port number.
  248. ; This proc doesn't guarantee that after calling it and trying to use
  249. ; the port reported being free in calls to socket_open/socket_open_tcp it'll
  250. ; still be free or otherwise it'll still be used if reported being in use.
  251. ;
  252. ; @param BX is a port number
  253. ; @return 1 (port is free) or 0 (port is in use) in EAX
  254. ;;
  255. proc is_localport_unused stdcall
  256.         xchg    bl, bh
  257.  
  258.         ; assume the return value is 'free'
  259.         xor     eax, eax
  260.         inc     al
  261.  
  262.         mov     edx, net_sockets
  263.  
  264.   .next_socket:
  265.         mov     edx, [edx + SOCKET.NextPtr]
  266.         or      edx, edx
  267.         jz      .exit
  268.         cmp     [edx + SOCKET.LocalPort], bx
  269.         jne     .next_socket
  270.  
  271.         ; return 'in use'
  272.         dec     al
  273.  
  274.   .exit:
  275.         ret
  276. endp
  277.  
  278. ;; [53.0] Open DGRAM socket (connectionless, unreliable)
  279. ;
  280. ; @param BX is local port number
  281. ; @param CX is remote port number
  282. ; @param EDX is remote IP address
  283. ; @return socket number or -1 (error) in EAX
  284. ;;
  285. proc socket_open stdcall
  286.         call    net_socket_alloc
  287.         or      eax, eax
  288.         jz      .error
  289.  
  290.         DEBUGF  1, "K : socket_open (0x%x)\n", eax
  291.  
  292.         push    eax
  293.  
  294.         xchg    bh, bl
  295.         mov     [eax + SOCKET.LocalPort], bx
  296.         xchg    ch, cl
  297.         mov     [eax + SOCKET.RemotePort], cx
  298.         mov     ebx, [stack_ip]
  299.         mov     [eax + SOCKET.LocalIP], ebx
  300.         mov     [eax + SOCKET.RemoteIP], edx
  301.  
  302.         ;pop     eax      ; Get the socket number back, so we can return it
  303.         stdcall net_socket_addr_to_num
  304.         ret
  305.  
  306.   .error:
  307.         DEBUGF  1, "K : socket_open (fail)\n"
  308.         or      eax, -1
  309.         ret
  310. endp
  311.  
  312. ;; [53.5] Open STREAM socket (connection-based, sequenced, reliable, two-way)
  313. ;
  314. ; @param BX is local port number
  315. ; @param CX is remote port number
  316. ; @param EDX is remote IP address
  317. ; @param ESI is open mode (SOCKET_ACTIVE, SOCKET_PASSIVE)
  318. ; @return socket number or -1 (error) in EAX
  319. ;;
  320. proc socket_open_tcp stdcall
  321. local sockAddr dd ?
  322.  
  323.         cmp     esi, SOCKET_PASSIVE
  324.         jne     .skip_port_check
  325.  
  326.         push    ebx
  327.         mov     eax, ebx
  328.         xchg    al, ah
  329.         mov     ebx, net_sockets
  330.  
  331.   .next_socket:
  332.         mov     ebx, [ebx + SOCKET.NextPtr]
  333.         or      ebx, ebx
  334.         jz      .last_socket
  335.         cmp     [ebx + SOCKET.TCBState], TCB_LISTEN
  336.         jne     .next_socket
  337.         cmp     [ebx + SOCKET.LocalPort], ax
  338.         jne     .next_socket
  339.  
  340.         xchg    al, ah
  341.         DEBUGF  1, "K : error: port %u is listened by 0x%x\n", ax, ebx
  342.         pop     ebx
  343.         jmp     .error
  344.  
  345.   .last_socket:
  346.         pop     ebx
  347.  
  348.   .skip_port_check:
  349.         call    net_socket_alloc
  350.         or      eax, eax
  351.         jz      .error
  352.  
  353.         DEBUGF  1, "K : socket_open_tcp (0x%x)\n", eax
  354.  
  355.         mov     [sockAddr], eax
  356.  
  357.         ; TODO - check this works!
  358.         ;mov     [eax + SOCKET.wndsizeTimer], 0     ; Reset the window timer.
  359.  
  360.         xchg    bh, bl
  361.         mov     [eax + SOCKET.LocalPort], bx
  362.         xchg    ch, cl
  363.         mov     [eax + SOCKET.RemotePort], cx
  364.         mov     [eax + SOCKET.OrigRemotePort], cx
  365.         mov     ebx, [stack_ip]
  366.         mov     [eax + SOCKET.LocalIP], ebx
  367.         mov     [eax + SOCKET.RemoteIP], edx
  368.         mov     [eax + SOCKET.OrigRemoteIP], edx
  369.  
  370.         mov     ebx, TCB_LISTEN
  371.         cmp     esi, SOCKET_PASSIVE
  372.         je      @f
  373.         mov     ebx, TCB_SYN_SENT
  374.     @@: mov     [eax + SOCKET.TCBState], ebx            ; Indicate the state of the TCB
  375.  
  376.         cmp     ebx, TCB_LISTEN
  377.         je      .exit
  378.  
  379.         ; Now, if we are in active mode, then we have to send a SYN to the specified remote port
  380.         mov     eax, EMPTY_QUEUE
  381.         call    dequeue
  382.         cmp     ax, NO_BUFFER
  383.         je      .exit
  384.  
  385.         push    eax
  386.  
  387.         mov     bl, TH_SYN
  388.         xor     ecx, ecx
  389.         stdcall build_tcp_packet, [sockAddr]
  390.  
  391.         mov     eax, NET1OUT_QUEUE
  392.         mov     edx, [stack_ip]
  393.         mov     ecx, [sockAddr]
  394.         cmp     edx, [ecx + SOCKET.RemoteIP]
  395.         jne     .not_local
  396.         mov     eax, IPIN_QUEUE
  397.  
  398.   .not_local:
  399.         ; Send it.
  400.         pop     ebx
  401.         call    queue
  402.  
  403.         mov     esi, [sockAddr]
  404.  
  405.         ; increment SND.NXT in socket
  406.         add     esi, SOCKET.SND_NXT
  407.         call    inc_inet_esi
  408.  
  409.   .exit:
  410.         ; Get the socket number back, so we can return it
  411.         stdcall net_socket_addr_to_num, [sockAddr]
  412.         ret
  413.  
  414.   .error:
  415.         DEBUGF  1, "K : socket_open_tcp (fail)\n"
  416.         or      eax, -1
  417.         ret
  418. endp
  419.  
  420. ;; [53.1] Close DGRAM socket
  421. ;
  422. ; @param EBX is socket number
  423. ; @return 0 (closed successfully) or -1 (error) in EAX
  424. ;;
  425. proc socket_close stdcall
  426.         DEBUGF  1, "K : socket_close (0x%x)\n", ebx
  427.         stdcall net_socket_num_to_addr, ebx
  428.         or      eax, eax
  429.         jz      .error
  430.  
  431.         stdcall net_socket_free, eax
  432.  
  433.         xor     eax, eax
  434.         ret
  435.  
  436.   .error:
  437.         DEBUGF  1, "K : socket_close (fail)\n"
  438.         or      eax, -1
  439.         ret
  440. endp
  441.  
  442. ;; [53.8] Close STREAM socket
  443. ; Closing TCP sockets takes time, so when you get successful return code
  444. ; from this function doesn't always mean that socket is actually closed.
  445. ;
  446. ; @param EBX is socket number
  447. ; @return 0 (closed successfully) or -1 (error) in EAX
  448. ;;
  449. proc socket_close_tcp stdcall
  450. local sockAddr dd ?
  451.  
  452.         DEBUGF  1, "K : socket_close_tcp (0x%x)\n", ebx
  453.         ; first, remove any resend entries
  454.         pusha
  455.  
  456.         mov     esi, resendQ
  457.         mov     ecx, 0
  458.  
  459.   .next_resendq:
  460.         cmp     ecx, NUMRESENDENTRIES
  461.         je      .last_resendq       ; None left
  462.         cmp     [esi + 4], ebx
  463.         je      @f                  ; found one
  464.         inc     ecx
  465.         add     esi, 8
  466.         jmp     .next_resendq
  467.  
  468.     @@: mov     dword[esi + 4], 0
  469.         inc     ecx
  470.         add     esi, 8
  471.         jmp     .next_resendq
  472.  
  473.   .last_resendq:
  474.         popa
  475.  
  476.         stdcall net_socket_num_to_addr, ebx
  477.         or      eax, eax
  478.         jz      .error
  479.  
  480.         mov     ebx, eax
  481.         mov     [sockAddr], eax
  482.  
  483.         cmp     [ebx + SOCKET.TCBState], TCB_LISTEN
  484.         je      .destroy_tcb
  485.         cmp     [ebx + SOCKET.TCBState], TCB_SYN_SENT
  486.         je      .destroy_tcb
  487.  
  488.         ; Now construct the response, and queue for sending by IP
  489.         mov     eax, EMPTY_QUEUE
  490.         call    dequeue
  491.         cmp     ax, NO_BUFFER
  492.         je      .error
  493.  
  494.         push    eax
  495.  
  496.         mov     bl, TH_FIN
  497.         xor     ecx, ecx
  498.         xor     esi, esi
  499.         stdcall build_tcp_packet, [sockAddr]
  500.  
  501.         mov      ebx, [sockAddr]
  502.         ; increament SND.NXT in socket
  503.         lea     esi, [ebx + SOCKET.SND_NXT]
  504.         call    inc_inet_esi
  505.  
  506.         ; Get the socket state
  507.         mov     eax, [ebx + SOCKET.TCBState]
  508.         cmp     eax, TCB_SYN_RECEIVED
  509.         je      .fin_wait_1
  510.         cmp     eax, TCB_ESTABLISHED
  511.         je      .fin_wait_1
  512.  
  513.         ; assume CLOSE WAIT
  514.         ; Send a fin, then enter last-ack state
  515.         mov     [ebx + SOCKET.TCBState], TCB_LAST_ACK
  516.         jmp     .send
  517.  
  518.   .fin_wait_1:
  519.         ; Send a fin, then enter finwait2 state
  520.         mov     [ebx + SOCKET.TCBState], TCB_FIN_WAIT_1
  521.  
  522.   .send:
  523.         mov     eax, NET1OUT_QUEUE
  524.         mov     edx, [stack_ip]
  525.         mov     ecx, [sockAddr]
  526.         cmp     edx, [ecx + SOCKET.RemoteIP]
  527.         jne     .not_local
  528.         mov     eax, IPIN_QUEUE
  529.  
  530.   .not_local:
  531.         ; Send it.
  532.         pop     ebx
  533.         call    queue
  534.         jmp     .exit
  535.  
  536.   .destroy_tcb:
  537.  
  538.         ; Clear the socket variables
  539.         stdcall net_socket_free, ebx
  540.  
  541.   .exit:
  542.         xor     eax, eax
  543.         ret
  544.  
  545.   .error:
  546.         DEBUGF  1, "K : socket_close_tcp (fail)\n"
  547.         or      eax, -1
  548.         ret
  549. endp
  550.  
  551. ;; [53.2] Poll socket
  552. ;
  553. ; @param EBX is socket number
  554. ; @return count or bytes in rx buffer or 0 (error) in EAX
  555. ;;
  556. proc socket_poll stdcall
  557. ;        DEBUGF  1, "socket_poll(0x%x)\n", ebx
  558.         stdcall net_socket_num_to_addr, ebx
  559.         or      eax, eax
  560.         jz      .error
  561.  
  562.         mov     eax, [eax + SOCKET.rxDataCount]
  563.         ret
  564.  
  565.   .error:
  566.         xor     eax, eax
  567.         ret
  568. endp
  569.  
  570. ;; [53.6] Get socket TCB state
  571. ;
  572. ; @param EBX is socket number
  573. ; @return socket TCB state or 0 (error) in EAX
  574. ;;
  575. proc socket_status stdcall
  576. ;;       DEBUGF  1, "socket_status(0x%x)\n", ebx
  577.         stdcall net_socket_num_to_addr, ebx
  578.         or      eax, eax
  579.         jz      .error
  580.  
  581.         mov     eax, [eax + SOCKET.TCBState]
  582.         ret
  583.  
  584.   .error:
  585.         xor     eax, eax
  586.         ret
  587. endp
  588.  
  589. ;; [53.3] Get one byte from rx buffer
  590. ; This function can return 0 in two cases: if there's one byte read and
  591. ; non left, and if an error occured. Behavior should be changed and function
  592. ; shouldn't be used for now. Consider using [53.11] instead.
  593. ;
  594. ; @param EBX is socket number
  595. ; @return number of bytes left in rx buffer or 0 (error) in EAX
  596. ; @return byte read in BL
  597. ;;
  598. proc socket_read stdcall
  599. ;        DEBUGF  1, "socket_read(0x%x)\n", ebx
  600.         stdcall net_socket_num_to_addr, ebx
  601.         or      eax, eax
  602.         jz      .error
  603.  
  604.         lea     ebx, [eax + SOCKET.lock]
  605.         call    wait_mutex
  606.  
  607.         mov     ebx, eax
  608.         mov     eax, [ebx + SOCKET.rxDataCount]         ; get count of bytes
  609.         test    eax, eax
  610.         jz      .error_release
  611.  
  612.         dec     eax
  613.         mov     esi, ebx                                ; esi is address of socket
  614.         mov     [ebx + SOCKET.rxDataCount], eax         ; store new count
  615.         movzx   eax, byte[ebx + SOCKET.rxData]          ; get the byte
  616.  
  617.         mov     ecx, SOCKETBUFFSIZE - SOCKET.rxData - 1
  618.         lea     edi, [esi + SOCKET.rxData]
  619.         lea     esi, [edi + 1]
  620.         cld
  621.         push    ecx
  622.         shr     ecx, 2
  623.         rep     movsd
  624.         pop     ecx
  625.         and     ecx, 3
  626.         rep     movsb
  627.  
  628.         mov     [ebx + SOCKET.lock], 0
  629.         mov     ebx, eax
  630.  
  631.         ret
  632.  
  633.   .error_release:
  634.         mov     [ebx + SOCKET.lock], 0
  635.   .error:
  636.         xor     ebx, ebx
  637.         ret
  638. endp
  639.  
  640. ;; [53.11] Get specified number of bytes from rx buffer
  641. ; Number of bytes in rx buffer can be less than requested size. In this case,
  642. ; only available number of bytes is read.
  643. ; This function can return 0 in two cases: if there's no data to read, and if
  644. ; an error occured. Behavior should be changed.
  645. ;
  646. ; @param EBX is socket number
  647. ; @param ECX is pointer to application buffer
  648. ; @param EDX is application buffer size (number of bytes to read)
  649. ; @return number of bytes read or 0 (error) in EAX
  650. ;;
  651. proc socket_read_packet stdcall
  652. ;        DEBUGF  1, "socket_read_packet(0x%x)\n", ebx
  653.         stdcall net_socket_num_to_addr, ebx                ; get real socket address
  654.         or      eax, eax
  655.         jz      .error
  656.  
  657.         lea     ebx, [eax + SOCKET.lock]
  658.         call    wait_mutex
  659.  
  660.         mov     ebx, eax
  661.         mov     eax, [ebx + SOCKET.rxDataCount]            ; get count of bytes
  662.         test    eax, eax                                   ; if count of bytes is zero..
  663.         jz      .exit                                      ; exit function (eax will be zero)
  664.  
  665.         test    edx, edx                                   ; if buffer size is zero, copy all data
  666.         jz      .copy_all_bytes
  667.         cmp     edx, eax                                   ; if buffer size is larger then the bytes of data, copy all data
  668.         jge     .copy_all_bytes
  669.  
  670.         sub     eax, edx                                   ; store new count (data bytes in buffer - bytes we're about to copy)
  671.         mov     [ebx + SOCKET.rxDataCount], eax            ;
  672.         push    eax
  673.         mov     eax, edx                                   ; number of bytes we want to copy must be in eax
  674.         call    .start_copy                                ; copy to the application
  675.  
  676.         mov     esi, ebx                                   ; now we're going to copy the remaining bytes to the beginning
  677.         add     esi, SOCKET.rxData                         ; we dont need to copy the header
  678.         mov     edi, esi                                   ; edi is where we're going to copy to
  679.         add     esi, edx                                   ; esi is from where we copy
  680.         pop     ecx                                        ; count of bytes we have left
  681.         push    ecx                                        ; push it again so we can re-use it later
  682.         shr     ecx, 2                                     ; divide eax by 4
  683.         cld
  684.         rep     movsd                                      ; copy all full dwords
  685.         pop     ecx
  686.         and     ecx, 3
  687.         rep     movsb                                      ; copy remaining bytes
  688.  
  689.   .exit:
  690.         mov     [ebx + SOCKET.lock], 0
  691.         ret                                                ; at last, exit
  692.  
  693.   .error:
  694.         xor     eax, eax
  695.         ret
  696.  
  697.   .copy_all_bytes:
  698.         xor     esi, esi
  699.         mov     [ebx + SOCKET.rxDataCount], esi            ; store new count (zero)
  700.         call    .start_copy
  701.         mov     [ebx + SOCKET.lock], 0
  702.         ret
  703.  
  704.   .start_copy:
  705.         mov     edi, ecx
  706.         mov     esi, ebx
  707.         add     esi, SOCKET.rxData                         ; we dont need to copy the header
  708.         mov     ecx, eax                                   ; eax is count of bytes
  709.         push    ecx
  710.         shr     ecx, 2                                     ; divide eax by 4
  711.         cld                                                ; copy all full dwords
  712.         rep     movsd
  713.         pop     ecx
  714.         and     ecx, 3
  715.         rep     movsb                                      ; copy the rest bytes
  716.         retn                                               ; exit, or go back to shift remaining bytes if any
  717. endp
  718.  
  719. ;; [53.4] Send data through DGRAM socket
  720. ;
  721. ; @param EBX is socket number
  722. ; @param ECX is application data size (number of bytes to send)
  723. ; @param EDX is pointer to application data buffer
  724. ; @return 0 (sent successfully) or -1 (error) in EAX
  725. ;;
  726. proc socket_write stdcall
  727. ;        DEBUGF  1, "socket_write(0x%x)\n", ebx
  728.         stdcall net_socket_num_to_addr, ebx                ; get real socket address
  729.         or      eax, eax
  730.         jz      .error
  731.  
  732.         mov     ebx, eax
  733.  
  734.         mov     eax, EMPTY_QUEUE
  735.         call    dequeue
  736.         cmp     ax, NO_BUFFER
  737.         je      .error
  738.  
  739.         ; Save the queue entry number
  740.         push    eax
  741.  
  742.         ; save the pointers to the data buffer & size
  743.         push    edx
  744.         push    ecx
  745.  
  746.         ; convert buffer pointer eax to the absolute address
  747.         mov     ecx, IPBUFFSIZE
  748.         mul     ecx
  749.         add     eax, IPbuffs
  750.  
  751.         mov     edx, eax
  752.  
  753.         ; So, ebx holds the socket ptr, edx holds the IPbuffer ptr
  754.  
  755.         ; Fill in the IP header (some data is in the socket descriptor)
  756.         mov     eax, [ebx + SOCKET.LocalIP]
  757.         mov     [edx + IP_PACKET.SourceAddress], eax
  758.         mov     eax, [ebx + SOCKET.RemoteIP]
  759.         mov     [edx + IP_PACKET.DestinationAddress], eax
  760.  
  761.         mov     [edx + IP_PACKET.VersionAndIHL], 0x45
  762.         mov     [edx + IP_PACKET.TypeOfService], 0
  763.  
  764.         pop     eax                   ; Get the UDP data length
  765.         push    eax
  766.  
  767.         add     eax, 20 + 8           ; add IP header and UDP header lengths
  768.         xchg    al, ah
  769.         mov     [edx + IP_PACKET.TotalLength], ax
  770.         xor     eax, eax
  771.         mov     [edx + IP_PACKET.Identification], ax
  772.         mov     [edx + IP_PACKET.FlagsAndFragmentOffset], 0x0040
  773.         mov     [edx + IP_PACKET.TimeToLive], 0x20
  774.         mov     [edx + IP_PACKET.Protocol], PROTOCOL_UDP
  775.  
  776.         ; Checksum left unfilled
  777.         mov     [edx + IP_PACKET.HeaderChecksum], ax
  778.  
  779.         ; Fill in the UDP header (some data is in the socket descriptor)
  780.         mov     ax, [ebx + SOCKET.LocalPort]
  781.         mov     [edx + 20 + UDP_PACKET.SourcePort], ax
  782.  
  783.         mov     ax, [ebx + SOCKET.RemotePort]
  784.         mov     [edx + 20 + UDP_PACKET.DestinationPort], ax
  785.  
  786.         pop     eax
  787.         push    eax
  788.  
  789.         add     eax, 8
  790.         xchg    al, ah
  791.         mov     [edx + 20 + UDP_PACKET.Length], ax
  792.  
  793.         ; Checksum left unfilled
  794.         xor     eax, eax
  795.         mov     [edx + 20 + UDP_PACKET.Checksum], ax
  796.  
  797.         pop     ecx                  ; count of bytes to send
  798.         mov     ebx, ecx             ; need the length later
  799.         pop     eax                  ; get callers ptr to data to send
  800.  
  801.         ; Get the address of the callers data
  802.         mov     edi, [TASK_BASE]
  803.         add     edi, TASKDATA.mem_start
  804.         add     eax, [edi]
  805.         mov     esi, eax
  806.  
  807.         mov     edi, edx
  808.         add     edi, 28
  809.         cld
  810.         rep     movsb               ; copy the data across
  811.  
  812.         ; we have edx as IPbuffer ptr.
  813.         ; Fill in the UDP checksum
  814.         ; First, fill in pseudoheader
  815.         mov     eax, [edx + IP_PACKET.SourceAddress]
  816.         mov     [pseudoHeader], eax
  817.         mov     eax, [edx + IP_PACKET.DestinationAddress]
  818.         mov     [pseudoHeader + 4], eax
  819.         mov     word[pseudoHeader + 8], PROTOCOL_UDP shl 8 + 0      ; 0 + protocol
  820.         add     ebx, 8
  821.         mov     eax, ebx
  822.         xchg    al, ah
  823.         mov     [pseudoHeader + 10], ax
  824.  
  825.         mov     eax, pseudoHeader
  826.         mov     [checkAdd1], eax
  827.         mov     [checkSize1], word 12
  828.         mov     eax, edx
  829.         add     eax, 20
  830.         mov     [checkAdd2], eax
  831.         mov     eax, ebx
  832.         mov     [checkSize2], ax      ; was eax!! mjh 8/7/02
  833.  
  834.         call    checksum
  835.  
  836.         ; store it in the UDP checksum ( in the correct order! )
  837.         mov     ax, [checkResult]
  838.  
  839.         ; If the UDP checksum computes to 0, we must make it 0xffff
  840.         ; (0 is reserved for 'not used')
  841.         test    ax, ax
  842.         jnz     @f
  843.         mov     ax, 0xffff
  844.  
  845.     @@: xchg    al, ah
  846.         mov     [edx + 20 + UDP_PACKET.Checksum], ax
  847.  
  848.         ; Fill in the IP header checksum
  849.         GET_IHL ecx,edx              ; get IP-Header length
  850.         stdcall checksum_jb,edx,ecx  ; buf_ptr, buf_size
  851.         xchg    al, ah
  852.         mov     [edx + IP_PACKET.HeaderChecksum], ax
  853.  
  854.         ; Check destination IP address.
  855.         ; If it is the local host IP, route it back to IP_RX
  856.  
  857.         pop     ebx
  858.  
  859.         mov     eax, NET1OUT_QUEUE
  860.         mov     ecx, [edx + SOCKET.RemoteIP]
  861.         mov     edx, [stack_ip]
  862.         cmp     edx, ecx
  863.         jne     .not_local
  864.         mov     eax, IPIN_QUEUE
  865.  
  866.   .not_local:
  867.         ; Send it.
  868.         call    queue
  869.  
  870.         xor     eax, eax
  871.         ret
  872.  
  873.   .error:
  874.         or      eax, -1
  875.         ret
  876. endp
  877.  
  878. ;; [53.7] Send data through STREAM socket
  879. ;
  880. ; @param EBX is socket number
  881. ; @param ECX is application data size (number of bytes to send)
  882. ; @param EDX is pointer to application data buffer
  883. ; @return 0 (sent successfully) or -1 (error) in EAX
  884. ;;
  885. proc socket_write_tcp stdcall
  886. local sockAddr dd ?
  887.  
  888. ;        DEBUGF  1, "socket_write_tcp(0x%x)\n", ebx
  889.         stdcall net_socket_num_to_addr, ebx
  890.         or      eax, eax
  891.         jz      .error
  892.  
  893.         mov     ebx, eax
  894.         mov     [sockAddr], ebx
  895.  
  896.         ; If the sockets window timer is nonzero, do not queue packet
  897.         cmp     [ebx + SOCKET.wndsizeTimer], 0
  898.         jne     .error
  899.  
  900.         mov     eax, EMPTY_QUEUE
  901.         call    dequeue
  902.         cmp     ax, NO_BUFFER
  903.         je      .error
  904.  
  905.         push    eax
  906.  
  907.         ; Get the address of the callers data
  908.         mov     edi, [TASK_BASE]
  909.         add     edi, TASKDATA.mem_start
  910.         add     edx, [edi]
  911.         mov     esi, edx
  912.  
  913.         pop     eax
  914.         push    eax
  915.  
  916.         push    ecx
  917.         mov     bl, TH_ACK
  918.         stdcall build_tcp_packet, [sockAddr]
  919.         pop     ecx
  920.  
  921.         ; Check destination IP address.
  922.         ; If it is the local host IP, route it back to IP_RX
  923.  
  924.         pop     ebx
  925.         push    ecx
  926.  
  927.         mov     eax, NET1OUT_QUEUE
  928.         mov     edx, [stack_ip]
  929.         mov     ecx, [sockAddr]
  930.         cmp     edx, [ecx + SOCKET.RemoteIP]
  931.         jne     .not_local
  932.         mov     eax, IPIN_QUEUE
  933.  
  934.   .not_local:
  935.         pop     ecx
  936.         push    ebx                 ; save ipbuffer number
  937.  
  938.         call    queue
  939.  
  940.         mov     esi, [sockAddr]
  941.  
  942.         ; increament SND.NXT in socket
  943.         ; Amount to increment by is in ecx
  944.         add     esi, SOCKET.SND_NXT
  945.         call    add_inet_esi
  946.  
  947.         pop     ebx
  948.  
  949.         ; Copy the IP buffer to a resend queue
  950.         ; If there isn't one, dont worry about it for now
  951.         mov     esi, resendQ
  952.         mov     ecx, 0
  953.  
  954.   .next_resendq:
  955.         cmp     ecx, NUMRESENDENTRIES
  956.         je      .exit              ; None found
  957.         cmp     dword[esi + 4], 0
  958.         je      @f                 ; found one
  959.         inc     ecx
  960.         add     esi, 8
  961.         jmp     .next_resendq
  962.  
  963.     @@: push    ebx
  964.  
  965.         ; OK, we have a buffer descriptor ptr in esi.
  966.         ; resend entry # in ecx
  967.         ;  Populate it
  968.         ;  socket #
  969.         ;  retries count
  970.         ;  retry time
  971.         ;  fill IP buffer associated with this descriptor
  972.  
  973.         stdcall net_socket_addr_to_num, [sockAddr]
  974.         mov     [esi + 4], eax
  975.         mov     byte[esi + 1], TCP_RETRIES
  976.         mov     word[esi + 2], TCP_TIMEOUT
  977.  
  978.         inc     ecx
  979.         ; Now get buffer location, and copy buffer across. argh! more copying,,
  980.         mov     edi, resendBuffer - IPBUFFSIZE
  981.  
  982.     @@: add     edi, IPBUFFSIZE
  983.         loop    @b
  984.  
  985.         ; we have dest buffer location in edi
  986.         pop     eax
  987.         ; convert source buffer pointer eax to the absolute address
  988.         mov     ecx, IPBUFFSIZE
  989.         mul     ecx
  990.         add     eax, IPbuffs
  991.         mov     esi, eax
  992.  
  993.         ; do copy
  994.         mov     ecx, IPBUFFSIZE
  995.         cld
  996.         rep     movsb
  997.  
  998.   .exit:
  999.         xor     eax, eax
  1000.         ret
  1001.  
  1002.   .error:
  1003.         or      eax, -1
  1004.         ret
  1005. endp
  1006.