Subversion Repositories Kolibri OS

Rev

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