Subversion Repositories Kolibri OS

Rev

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