; _______________________________________________________________________________________
;|                                                                                       |
;| ..::FreshLib::..  Free, open source. Licensed under "BSD 2-clause" license."          |
;|_______________________________________________________________________________________|
;
;  Description: OS dependent part of the network library.
;
;  Target OS: Linux
;
;  Dependencies:
;
;  Notes:
;_________________________________________________________________________________________


serrAccess              = EACCES
serrNoMemory            = ENOMEM
serrProtocolNotSupported= EPROTONOSUPPORT

serrAddessInUse         = EADDRINUSE
serrNotASocket          = ENOTSOCK

serrWouldBlock          = EWOULDBLOCK
serrBadSocket           = EBADF
serrConnRefused         = ECONNREFUSED
serrConnReset           = ECONNRESET
serrDestAddrReq         = EDESTADDRREQ
serrInvalidAddress      = EFAULT
serrInterrupt           = EINTR
serrInvalidArgument     = EINVAL
serrIsConnected         = EISCONN

serrTimeout = EWOULDBLOCK


proc __SocketError
begin
        test    eax, eax
        jns     .no_error
        neg     eax
        stc
        return

.no_error:
        clc
        return
endp


body SocketCreate
begin
        push    ebx ecx edx

        mov     eax, sys_socketcall
        mov     ebx, SYS_SOCKET
        lea     ecx, [.protocol_family]
        int     $80

        call    __SocketError
        pop     edx ecx ebx
        return
endp



body SocketClose
;.buffer rb 1024
;.params rd 2
begin
        push    ebx ecx edx

;        push    [.hSocket]
;        pop     [.params]
;        mov     [.params+4], 1
;
;        mov     eax, sys_socketcall
;        mov     ebx, SYS_SHUTDOWN
;        lea     ecx, [.params]
;        int     $80
;        call    __SocketError
;        jc      .finish
;
;.loop:
;        lea     ecx, [.buffer]
;        stdcall SocketReceive, [.hSocket], ecx, 1024, 0
;        jc      .finish
;        test    eax, eax
;        jnz     .loop
;
;.finish:

        mov     eax, sys_close
        mov     ebx, [.hSocket]
        int     $80
        call    __SocketError

        pop     edx ecx ebx
        return
endp



body SocketConnect
.sock dd ?
.addr dd ?
.size dd ?
begin
        push    ebx ecx edx

        push    [.hSocket] [.pAddress]
        pop     [.addr] [.sock]
        mov     [.size], sizeof.TSocketAddress

        mov     eax, sys_socketcall
        mov     ebx, SYS_CONNECT
        lea     ecx, [.sock]
        int     $80

        call    __SocketError
        pop     edx ecx ebx
        return
endp



body SocketBind
.socket   dd ?
.paddr    dd ?
.addrsize dd ?
begin
        push    ebx ecx edx

        mov     eax, [.hSocket]
        mov     ebx, [.pAddress]
        mov     [.socket], eax
        mov     [.paddr], ebx

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

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

        mov     eax, -EINVAL
        cmp     [ebx+TSocketAddress.saFamily], AF_UNIX
        jne     .finish

        mov     ecx, sizeof.TSocketAddressUn

.do_bind:
        mov     [.addrsize], ecx

        mov     eax, sys_socketcall
        mov     ebx, SYS_BIND
        lea     ecx, [.socket]
        int     $80

.finish:
        call    __SocketError
        pop     edx ecx ebx
        return
endp



body SocketListen
begin
        push    ebx ecx edx

        mov     eax, sys_socketcall
        mov     ebx, SYS_LISTEN
        lea     ecx, [.hSocket]
        int     $80

        call    __SocketError
        pop     edx ecx ebx
        return
endp



body SocketAccept
.sock    dd ?
.addr    dd ?
.addrlen dd ?
begin
        push    ebx edx

        push    [.hSocket] [.pAddress]
        pop     [.addr] [.sock]
        mov     [.addrlen], sizeof.TSocketAddress

        cmp     [.addr], 0
        jne     @f
        mov     [.addrlen], 0
@@:
        mov     eax, sys_socketcall
        mov     ebx, SYS_ACCEPT
        lea     ecx, [.sock]
        int     $80

        call    __SocketError
        mov     ecx, [.addrlen]

        pop     edx ebx
        return
endp



body SocketSend
begin
        push    ebx ecx edx

        or      [.flags], MSG_NOSIGNAL
        mov     eax, sys_socketcall
        mov     ebx, SYS_SEND
        lea     ecx, [.hSocket]
        int     $80
        call    __SocketError
        pop     edx ecx ebx
        return
endp


body SocketReceive
begin
        push    ebx ecx edx
        mov     eax, sys_socketcall
        mov     ebx, SYS_RECV
        lea     ecx, [.hSocket]
        int     $80
        call    __SocketError
        pop     edx ecx ebx
        return
endp


body SocketSendTo
.sock  dd ?
.buff  dd ?
.len   dd ?
.flgs  dd ?
.addr  dd ?
.alen  dd ?
begin
        push    ebx ecx edx

        lea     ecx, [.sock]
        mov     edx, 16

.copy:
        mov     eax, [.hSocket+4*edx]
        mov     [ecx+4*edx], eax
        dec     edx
        jns     .copy
        mov     [.alen], sizeof.TSocketAddress

        mov     eax, sys_socketcall
        mov     ebx, SYS_SENDTO
        int     $80
        call    __SocketError

        pop     edx ecx ebx
        return
endp


body SocketReceiveFrom
.sock  dd ?
.buff  dd ?
.len   dd ?
.flgs  dd ?
.addr  dd ?
.alen  dd ?
begin
        push    ebx edx

        lea     ecx, [.sock]
        mov     edx, 16

.copy:
        mov     eax, [.hSocket+4*edx]
        mov     [ecx+4*edx], eax
        dec     edx
        jns     .copy
        mov     [.alen], sizeof.TSocketAddress

        mov     eax, sys_socketcall
        mov     ebx, SYS_RECVFROM
        int     $80
        call    __SocketError
        mov     ecx, [.alen]
        pop     edx ebx
        return
endp



body SocketGetOption
.socket     dd ?
.level      dd ?
.option     dd ?
.ptr_buffer dd ?
.ptr_size   dd ?

.ret_size dd ?
.buffer   rd 4
begin
        push    ebx ecx edx

        mov     eax, [.hSocket]
        mov     ebx, [.idOption]
        lea     ecx, [.buffer]

        mov     [.socket], eax
        mov     [.level], SOL_SOCKET
        mov     [.option], ebx
        mov     [.ptr_buffer], ecx
        lea      eax, [.ret_size]
        mov      [.ptr_size], eax
        mov      [.ret_size], 16

        mov     eax, sys_socketcall
        mov     ebx, SYS_GETSOCKOPT
        lea     ecx, [.socket]
        int     $80

        call    __SocketError
        jc      .finish

        cmp     [.idOption], soSendTimeout
        je      .timeouts
        cmp     [.idOption], soRecvTimeout
        je      .timeouts
        cmp     [.idOption], soLinger
        je      .linger

        mov     eax, [.buffer]
        clc

.finish:
        pop     edx ecx ebx
        return

.timeouts:
        mov     eax, [.buffer+lnx_timeval.tv_usec]
        cdq
        mov     ecx, 1000
        idiv    ecx
        mov     edx, [.buffer+lnx_timeval.tv_sec]
        imul    edx, 1000
        add     eax, edx
        clc
        jmp     .finish

.linger:
        mov     eax, [.buffer]          ; linger flag
        test    eax, eax
        jz      .finish

        mov     eax, [.buffer+4]
        clc
        jmp     .finish
endp



body SocketSetOption
.socket     dd ?
.level      dd ?
.option     dd ?
.ptr_buffer dd ?
.buf_size   dd ?

.buffer rd 4
begin
        push    ebx ecx edx

        mov     eax, [.hSocket]
        mov     ebx, [.idOption]
        lea     ecx, [.buffer]

        mov     [.socket], eax
        mov     [.level], SOL_SOCKET
        mov     [.option], ebx
        mov     [.ptr_buffer], ecx

        cmp     ebx, soRecvTimeout
        je      .timeouts
        cmp     ebx, soSendTimeout
        jne     .not_timeout

.timeouts:
        mov     eax, [.Value]   ; time in [ms]
        cdq
        mov     ecx, 1000
        div     ecx

        imul    edx, 1000       ; in [us]

        lea     ecx, [.buffer]
        mov     [ecx+lnx_timeval.tv_sec], eax   ; the seconds.
        mov     [ecx+lnx_timeval.tv_usec], edx  ; the microseconds.
        mov     [.buf_size], sizeof.lnx_timeval
        jmp     .call_socket

.not_timeout:
        cmp     ebx, soLinger
        jne     .not_linger

        mov     eax, [.Value]
        mov     [.buffer], eax
        mov     [.buffer+4], eax
        mov     [.buf_size], 8
        jmp     .call_socket

.not_linger:
        mov     eax, [.Value]
        mov     [.buffer], eax
        mov     [.buf_size], 4

.call_socket:
        mov     eax, sys_socketcall
        mov     ebx, SYS_SETSOCKOPT
        lea     ecx, [.socket]
        int     $80

        call    __SocketError

        pop     edx ecx ebx
        return
endp