Subversion Repositories Kolibri OS

Rev

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