; _______________________________________________________________________________________
;|                                                                                       |
;| ..::FreshLib::..  Free, open source. Licensed under "BSD 2-clause" license."          |
;|_______________________________________________________________________________________|
;
;  Description: OS dependent part of the network library.
;
;  Target OS: Win32
;
;  Dependencies:
;
;  Notes: This library follows the rules of Berkley sockets library with some small
;         differences (for example in the return values)
;_________________________________________________________________________________________

uses wsock32

serrTimeout = 10060




uglobal
  __wsaData WSADATA
endg


if used SocketCreate

initialize InitWindowsSockets
begin
        invoke  WSAStartup, $0101, __wsaData
        test    eax, eax
        jz      @f
        int3
@@:
        return
endp


finalize FinishWindowsSockets
begin
        invoke  WSACleanup
        return
endp

end if


proc __SocketError
begin
        cmp     eax, SOCKET_ERROR
        jne     .no_error

        push    ecx edx
        invoke  WSAGetLastError
        pop     edx ecx
        stc
        return

.no_error:
        clc
        return
endp


body SocketCreate
begin
        push    ecx edx
        invoke  socket, [.protocol_family], [.socket_type], [.protocol]
        call    __SocketError
        pop     edx ecx
        return
endp



body SocketClose
.buffer rb 1024
begin
        push    ecx edx
        invoke  shutdown, [.hSocket], 1
        call    __SocketError
        jc      .finish

.loop:
        lea     ecx, [.buffer]
        invoke  recv, [.hSocket], ecx, 1024, 0
        call    __SocketError
        jc      .finish
        test    eax, eax
        jnz     .loop

.finish:
        invoke  closesocket, [.hSocket]
        call    __SocketError

        pop     edx ecx
        return
endp



body SocketConnect
begin
        push    ecx edx
        invoke  connect, [.hSocket], [.pAddress], sizeof.TSocketAddress
        call    __SocketError
        pop     edx ecx
        return
endp



body SocketBind
begin
        push    ecx edx

        mov     edx, [.pAddress]

        mov     ecx, sizeof.TSocketAddressIn
        cmp     [edx+TSocketAddress.saFamily], AF_INET
        je      .do_bind

        mov     ecx, sizeof.TSocketAddressIn6
        cmp     [edx+TSocketAddress.saFamily], AF_INET6
        je      .do_bind

        mov     ecx, sizeof.TSocketAddressUn
        cmp     [edx+TSocketAddress.saFamily], AF_UNIX
        je      .do_bind

        invoke  WSASetLastError, WSAEINVAL
        jmp     .finish

.do_bind:
        invoke  bind, [.hSocket], [.pAddress], ecx

.finish:
        call    __SocketError
        pop     edx ecx
        return
endp



body SocketListen
begin
        push    ecx edx
        invoke  listen, [.hSocket], [.maxPending]
        call    __SocketError
        pop     edx ecx
        return
endp



body SocketAccept
.addrlen dd ?
begin
        push    edx

        mov     [.addrlen], sizeof.TSocketAddress
        lea     ecx, [.addrlen]
        cmp     [.pAddress], 0
        jne     @f
        xor     ecx, ecx
        mov     [.addrlen], ecx
@@:
        invoke  accept, [.hSocket], [.pAddress], ecx
        mov     ecx, [.addrlen]
        call    __SocketError
        pop     edx
        return
endp



body SocketSend
begin
        push    ecx edx
        invoke  send, [.hSocket], [.pBuffer], [.DataLen], [.flags]
        call    __SocketError
        pop     edx ecx
        return
endp


body SocketReceive
begin
        push    ecx edx
        invoke  recv, [.hSocket], [.pBuffer], [.BufferSize], [.flags]
        call    __SocketError
        pop     edx ecx
        return
endp


body SocketSendTo
begin
        push    ecx edx
        invoke  sendto, [.hSocket], [.pBuffer], [.DataLen], [.flags], [.pAddressTo], sizeof.TSocketAddress
        call    __SocketError
        pop     edx ecx
        return
endp


body SocketReceiveFrom
.addrlen dd ?
begin
        push    edx
        mov     [.addrlen], sizeof.SocketAddress
        lea     ecx,  [.addrlen]
        invoke  recvfrom, [.hSocket], [.pBuffer], [.BufferSize], [.flags], [.pAddressFrom], ecx
        call    __SocketError
        mov     ecx, [.addrlen]
        pop     edx
        return
endp


;body SetLinger
;begin
;        push    ecx edx
;        lea     ecx, [.fLinger]
;        invoke  setsockopt, [.hSocket], SOL_SOCKET, SO_LINGER, ecx, 8
;        call    __SocketError
;        pop     edx ecx
;        return
;endp


body SocketGetOption
.len    dd ?
.option rd 4
begin
        push    ecx edx

        mov     [.len], 16

        lea     eax, [.option]
        lea     ecx, [.len]
        invoke  getsockopt, [.hSocket], SOL_SOCKET, [.idOption], eax, ecx
        call    __SocketError
        jc      .finish
        mov     eax, [.option]
.finish:
        pop     edx ecx
        return
endp



body SocketSetOption
.option rd 4
begin
        push    ecx edx

        mov     eax, [.Value]
        mov     [.option], eax
        mov     ecx, 4

        cmp     [.idOption], soLinger
        jne     .callit

        mov     [.option+4], eax
        mov     ecx, 8

.callit:
        lea     eax, [.option]
        invoke  setsockopt, [.hSocket], SOL_SOCKET, [.idOption], eax, ecx
        call    __SocketError
        pop     edx ecx
        return
endp