
// TODO: Different size for different platforms. Use minimal size?
VAR_GLOBAL CONSTANT
    HSAL_UNIX_PATH_MAX  :DWORD:=64;
    HSAL_SOCKET_SET_SIZE:DWORD:=16;
END_VAR


/**
 * @brief Семейство протоколов

typedef enum {
    AF_UNSPEC := 0,
    AF_UNIX,
    AF_INET,
    AF_INET6
    // Anything else?
} HSAL_Socket_Domain;*/

TYPE HSAL_Socket_Domain:
(
	AF_UNSPEC := 0,
    AF_UNIX,
    AF_INET,
    AF_INET6
);
END_TYPE

/**
 * @brief Тип сокета, задающий семантику коммуникации

typedef enum {
    SOCK_STREAM := 0,
    HSAL_SOCK_DGRAM,
    HSAL_SOCK_SEQPACKET,
    HSAL_SOCK_RAW
    // Anything else?
} HSAL_Socket_Type;*/

TYPE HSAL_Socket_Type:
(
    SOCK_STREAM := 0,
    HSAL_SOCK_DGRAM,
    HSAL_SOCK_SEQPACKET,
    HSAL_SOCK_RAW
);
END_TYPE

/**
 * @brief Протокол
 * @note DFLT - для протокола по умолчанию из указанного семейства (HSAL_Socket_Domain) и типа (HSAL_Socket_Type)

typedef enum {
    DFLT := 0,
    ICMP,
    TCP,
    UDP
    // Anything else?
} HSAL_Socket_Protocol;*/

TYPE HSAL_Socket_Protocol:
(
    DFLT := 0,
    ICMP,
    TCP,
    UDP
);
END_TYPE

/**
 * @brief Уровень протокола

typedef enum {
    SOCKET := 0,
    TCP,
    UDP
    // Anything else?
} HSAL_SOL;*/

TYPE HSAL_SOL:
(
    SOCKET := 0,
    TCP,
    UDP
);
END_TYPE

/**
 * @brief Флаги сокета уровня SOCKET

typedef enum {
    SOCKET_REUSEADDR := 0
    // Anything else?
} HSAL_SOL_SOCKET_Flags;*/

TYPE HSAL_SOL_SOCKET_Flags:
(
    REUSEADDR := 0
);
END_TYPE

/**
 * @brief Флаги сокета уровня TCP

typedef enum {
    HSAL_SOL_TCP_NODELAY := 0
    // Anything else?
} HSAL_SOL_TCP_Flags;*/

TYPE HSAL_SOL_TCP_Flags:
(
    NODELAY := 0
);
END_TYPE

/**
 * @brief Флаги сокета уровня HSAL_SOL_UDP

typedef enum {
    UDP_ENCAP := 0
    // Anything else?
} HSAL_SOL_UDP_Flags;*/

TYPE HSAL_SOL_UDP_Flags:
(
    UDP_ENCAP := 0
);
END_TYPE

/**
 * @brief Флаги, используемые при получении и отправке сообщений из сокета

typedef enum {
    OOB       :=16#0001,
    PEEK      :=16#0002,
    DONTROUTE :=16#0004,
    TRUNC     :=16#0020,
    DONTWAIT  :=16#0040,
    WAITALL   :=16#0100
    // Anything else?
} HSAL_Socket_SR_Flags;*/

TYPE HSAL_Socket_SR_Flags:
(
    OOB       :=16#0001,
    PEEK      :=16#0002,
    DONTROUTE :=16#0004,
    TRUNC     :=16#0020,
    DONTWAIT  :=16#0040,
    WAITALL   :=16#0100
);
END_TYPE

/**
 * @brief Способ закрытия сокета

typedef enum {
    RD := 0,
    WR,
    RDWR
} HSAL_Socket_Shutdown;*/

TYPE HSAL_Socket_Shutdown:
(
    RD := 0,
    WR,
    RDWR
);
END_TYPE
/**
 * @brief Адрес сокета для UNIX

typedef struct {
	char path[HSAL_UNIX_PATH_MAX];
} HSAL_SA_UNIX;*/

TYPE HSAL_SA_UNIX:
STRUCT 
	path: STRING[HSAL_UNIX_PATH_MAX]; 
END_STRUCT
END_TYPE

/**
 * @brief Адрес сокета для INET

typedef struct {
    uint16_t port;
    uint32_t addr;
} HSAL_SA_INET;*/

TYPE HSAL_SA_INET:
STRUCT 
	port: WORD;
    addr: DWORD;
END_STRUCT
END_TYPE
/**
 * @brief Адрес сокета для INET6

typedef struct {
    uint16_t port;
    uint32_t flow_info;
    uint8_t addr[16];
    uint32_t scope_id;
} HSAL_SA_INET6;*/

TYPE HSAL_SA_INET6:
STRUCT 
	port        : WORD;
    flow_info   : DWORD;
    addr        : ARRAY [0..15] OF BYTE;
    scope_id    : DWORD;
END_STRUCT
END_TYPE

/**
 * @brief Продолжительность промежутка времени

typedef struct {
    uint32_t sec;
    uint32_t usec;
} HSAL_Socket_Time;*/

TYPE HSAL_Socket_Time:
STRUCT 
    sec   :DWORD;
    usec  :DWORD;
END_STRUCT
END_TYPE

/**
 * @brief Дескриптор сокета. Обобщенный тип для хранения дескриптора сокета в разных системах
 * @param id Указатель на дескриптор сокета (или дескриптор сокета), используемый в конкретной системе

typedef struct {
    uintptr_t id; //Нельзя указатель т.к. это в реальности DINT
} HSAL_Socket_ID;*/

TYPE HSAL_Socket_ID:
STRUCT 
    id   : uintptr_t;
END_STRUCT
END_TYPE

/**
 * @brief Атрибуты сокета

typedef struct {
    HSAL_Socket_Domain domain;
} HSAL_Socket_Attrs;*/

TYPE HSAL_Socket_Attrs:
STRUCT 
    domain  :HSAL_Socket_Domain;
END_STRUCT
END_TYPE




//int ( *socket)(struct HSAL_Socket *socket, HSAL_Socket_Domain domain, HSAL_Socket_Type type, HSAL_Socket_Protocol protocol, bool blocking);
@EXTERNAL FUNCTION typedef_HSAL_Socket_socket : DINT
VAR_INPUT 
	socket      :REF_TO HSAL_Socket;
    domain      :HSAL_Socket_Domain;
    _type       :HSAL_Socket_Type;
    protocol    :HSAL_Socket_Protocol;
    blocking    :BOOL;
END_VAR
END_FUNCTION
//int ( *bind)(struct HSAL_Socket *socket, const void *address);
@EXTERNAL FUNCTION typedef_HSAL_Socket_bind : DINT
VAR_INPUT 
	socket      :REF_TO HSAL_Socket;
END_VAR
VAR_INPUT 
    address     :REF_TO VOID; 
END_VAR
END_FUNCTION
//int ( *listen)(struct HSAL_Socket *socket, int backlog);
@EXTERNAL FUNCTION typedef_HSAL_Socket_listen : DINT
VAR_INPUT 
	socket      :REF_TO HSAL_Socket;
    backlog     : DINT;
END_VAR
END_FUNCTION
//int ( *accept)(struct HSAL_Socket *socket, struct HSAL_Socket *new_socket, void *address, bool blocking);
@EXTERNAL FUNCTION typedef_HSAL_Socket_accept : DINT
VAR_INPUT 
	socket      :REF_TO HSAL_Socket;
    new_socket  :REF_TO HSAL_Socket;
    address     :REF_TO VOID; 
    blocking    :BOOL;
END_VAR
END_FUNCTION
//int ( *connect)(struct HSAL_Socket *socket, const void *address);
@EXTERNAL FUNCTION typedef_HSAL_Socket_connect : DINT
VAR_INPUT 
	socket:REF_TO HSAL_Socket;
END_VAR
VAR_INPUT 
    address     :REF_TO VOID; 
END_VAR
END_FUNCTION
//int ( *close)(struct HSAL_Socket *socket);
@EXTERNAL FUNCTION typedef_HSAL_Socket_close : DINT
VAR_INPUT 
	socket      :REF_TO HSAL_Socket;
END_VAR
END_FUNCTION
//int ( *getsockopt)(struct HSAL_Socket *socket, HSAL_SOL level, int optname, void *optval, size_t *optlen);
@EXTERNAL FUNCTION typedef_HSAL_Socket_getsockopt : DINT
VAR_INPUT 
	socket      :REF_TO HSAL_Socket;
    level       :HSAL_SOL;
    optname     :DINT;
    optval      :REF_TO VOID;
    optlen      :REF_TO size_t;
END_VAR
END_FUNCTION
//int ( *setsockopt)(struct HSAL_Socket *socket, HSAL_SOL level, int optname, const void *optval, size_t optlen);
@EXTERNAL FUNCTION typedef_HSAL_Socket_setsockopt : DINT
VAR_INPUT 
	socket      :REF_TO HSAL_Socket;
    level       :HSAL_SOL;
    optname     :DINT;
   optval       :REF_TO VOID;
   optlen       :REF_TO size_t;
END_VAR
END_FUNCTION
//int ( *getpeername)(struct HSAL_Socket *socket, void *address);
@EXTERNAL FUNCTION typedef_HSAL_Socket_getpeername : DINT
VAR_INPUT 
	socket      :REF_TO HSAL_Socket;
    address     :REF_TO VOID;
END_VAR
END_FUNCTION
//int ( *getsockname)(struct HSAL_Socket *socket, void *address);
@EXTERNAL FUNCTION typedef_HSAL_Socket_getsockname : DINT
VAR_INPUT 
	socket      :REF_TO HSAL_Socket;
    address     :REF_TO VOID;
END_VAR
END_FUNCTION
//int ( *ntop)(HSAL_Socket_Domain domain, const void *src, char *dst, size_t cnt);
@EXTERNAL FUNCTION typedef_HSAL_Socket_ntop: DINT
VAR_INPUT 
	domain      :HSAL_Socket_Domain;
    src         :REF_TO VOID;
    dst         :REF_TO BYTE;
    cnt         : size_t; 
END_VAR
END_FUNCTION
//int ( *pton)(HSAL_Socket_Domain domain, const char *src, void *dst);
@EXTERNAL FUNCTION typedef_HSAL_Socket_pton : DINT
VAR_INPUT 
	domain      :HSAL_Socket_Domain;
    src         :REF_TO VOID;
    dst         :REF_TO BYTE;
END_VAR
END_FUNCTION
//int ( *recv)(struct HSAL_Socket *socket, void *buf, size_t len, int flags);
@EXTERNAL FUNCTION typedef_HSAL_Socket_recv : DINT
VAR_INPUT 
	socket      :REF_TO HSAL_Socket;
    buf         :REF_TO VOID;
    len         : size_t;
    flags       :DINT;
END_VAR
END_FUNCTION
//int ( *recvfrom)(struct HSAL_Socket *socket, void *buf, size_t len, int flags, void *address);
@EXTERNAL FUNCTION typedef_HSAL_Socket_recvfrom : DINT
VAR_INPUT 
	socket      :REF_TO HSAL_Socket;
    buf         :REF_TO VOID;
    len         : size_t;
    flags       :DINT;
    address     :REF_TO VOID;
END_VAR
END_FUNCTION
//ssize_t ( *send)(struct HSAL_Socket *socket, const void *msg, size_t len, int flags);
@EXTERNAL FUNCTION typedef_HSAL_Socket_send : DINT
VAR_INPUT 
	socket      :REF_TO HSAL_Socket;
	msg         :REF_TO VOID;
    len         : size_t;
    flags       :DINT;
END_VAR
END_FUNCTION
//ssize_t ( *sendto)(struct HSAL_Socket *socket, const void *msg, size_t len, int flags, const void *address);
@EXTERNAL FUNCTION typedef_HSAL_Socket_sendto : DINT
VAR_INPUT 
	socket      :REF_TO HSAL_Socket;
	msg         :REF_TO VOID;
    len         : size_t;
    flags       :DINT;
END_VAR
VAR_INPUT 
	address     :REF_TO VOID;
END_VAR
END_FUNCTION
//int ( *shutdown)(struct HSAL_Socket *socket, HSAL_Socket_Shutdown how);
@EXTERNAL FUNCTION typedef_HSAL_Socket_shutdown : DINT
VAR_INPUT 
	socket      :REF_TO HSAL_Socket;
    how         :HSAL_Socket_Shutdown;
END_VAR
END_FUNCTION

TYPE HSAL_Socket:
STRUCT 
    __socket    :HSAL_Socket_ID ;
    __attrs     :HSAL_Socket_Attrs ;
    socket      :REF_TO typedef_HSAL_Socket_socket;          //int ( *socket)(struct HSAL_Socket *s, HSAL_Socket_Domain domain, HSAL_Socket_Type type, HSAL_Socket_Protocol protocol, bool blocking);
    bind        :REF_TO typedef_HSAL_Socket_bind;            //int ( *bind)(struct HSAL_Socket *socket, const void *address);
    listen      :REF_TO typedef_HSAL_Socket_listen;         //int ( *listen)(struct HSAL_Socket *socket, int backlog);
    accept      :REF_TO typedef_HSAL_Socket_accept;               //int ( *accept)(struct HSAL_Socket *socket, struct HSAL_Socket *new_socket, void *address, bool blocking);
    connect     :REF_TO typedef_HSAL_Socket_connect;               //int ( *connect)(struct HSAL_Socket *socket, const void *address);
    close       :REF_TO typedef_HSAL_Socket_close;             //int ( *close)(struct HSAL_Socket *socket);
    getsockopt   :REF_TO typedef_HSAL_Socket_getsockopt;               //int ( *getsockopt)(struct HSAL_Socket *socket, HSAL_SOL level, int optname, void *optval, size_t *optlen);
    setsockopt   :REF_TO typedef_HSAL_Socket_setsockopt ;               //int ( *setsockopt)(struct HSAL_Socket *socket, HSAL_SOL level, int optname, const void *optval, size_t optlen);
    getpeername   :REF_TO typedef_HSAL_Socket_getpeername;               //int ( *getpeername)(struct HSAL_Socket *socket, void *address);
    getsockname   :REF_TO typedef_HSAL_Socket_getsockname;               //int ( *getsockname)(struct HSAL_Socket *socket, void *address);
    ntop        :REF_TO typedef_HSAL_Socket_ntop;               //int ( *ntop)(HSAL_Socket_Domain domain, const void *src, char *dst, size_t cnt);
    pton        :REF_TO typedef_HSAL_Socket_pton;               //int ( *pton)(HSAL_Socket_Domain domain, const char *src, void *dst);
    recv        :REF_TO typedef_HSAL_Socket_recv;               //int ( *recv)(struct HSAL_Socket *socket, void *buf, size_t len, int flags);
    recvfrom    :REF_TO typedef_HSAL_Socket_recvfrom;                //int ( *recvfrom)(struct HSAL_Socket *socket, void *buf, size_t len, int flags, void *address);
    send        :REF_TO typedef_HSAL_Socket_send;             //ssize_t ( *send)(struct HSAL_Socket *socket, const void *msg, size_t len, int flags);
    sendto      :REF_TO typedef_HSAL_Socket_sendto;                //ssize_t ( *sendto)(struct HSAL_Socket *socket, const void *msg, size_t len, int flags, const void *address);
    shutdown    :REF_TO typedef_HSAL_Socket_shutdown;               //int ( *shutdown)(struct HSAL_Socket *socket, HSAL_Socket_Shutdown how);
END_STRUCT
END_TYPE

/**
 * @brief Конструктор сокета  
 * @param [in] socket Описатель сокета
 * @return Результат
 * := 0 - Успешное завершение
 * < 0 - Код ошибки
 */
//int hsal_socket_constructor(HSAL_Socket *socket);
@EXTERNAL FUNCTION hsal_socket_constructor : DINT
VAR_INPUT 
	socket      :REF_TO HSAL_Socket;
END_VAR
END_FUNCTION

/**
 * @brief Атрибуты набора сокетов
 * @param count Количество сокетов в наборе
 * @param sockets Набор сокетов

typedef struct {
    HSAL_Socket *sockets[HSAL_SOCKET_SET_SIZE];
} HSAL_Socket_Set_Attrs;*/

TYPE HSAL_Socket_Set_Attrs:
STRUCT 
	sockets: ARRAY [0..HSAL_SOCKET_SET_SIZE-1] OF REF_TO HSAL_Socket; 
END_STRUCT
END_TYPE






//void ( *clear)(struct HSAL_Socket_Set *set, HSAL_Socket *socket);
@EXTERNAL FUNCTION typedef_HSAL_Socket_Set_clear : VOID
VAR_INPUT 
    set:        REF_TO HSAL_Socket_Set;
	socket      :REF_TO HSAL_Socket;
END_VAR
END_FUNCTION
//bool ( *is_set)(struct HSAL_Socket_Set *set, HSAL_Socket *socket);
@EXTERNAL FUNCTION typedef_HSAL_Socket_Set_is_set : BOOL
VAR_INPUT 
    set         :REF_TO HSAL_Socket_Set;
	socket      :REF_TO HSAL_Socket;
END_VAR
END_FUNCTION
//void ( *set)(struct HSAL_Socket_Set *set, HSAL_Socket *socket);
@EXTERNAL FUNCTION typedef_HSAL_Socket_Set_set : VOID
VAR_INPUT
    set         :REF_TO HSAL_Socket_Set; 
	socket      :REF_TO HSAL_Socket;
END_VAR
END_FUNCTION
//void ( *zero)(struct HSAL_Socket_Set *set);
@EXTERNAL FUNCTION typedef_HSAL_Socket_Set_zero : VOID
VAR_INPUT 
	set:        REF_TO HSAL_Socket_Set;
END_VAR
END_FUNCTION
//int ( *select)(struct HSAL_Socket_Set *read_set, struct HSAL_Socket_Set *write_set, struct HSAL_Socket_Set *except_set, const HSAL_Socket_Time *timeout);
@EXTERNAL FUNCTION typedef_HSAL_Socket_Set_select : DINT
VAR_INPUT 
    read_set    :REF_TO HSAL_Socket_Set;
    write_set   :REF_TO HSAL_Socket_Set;
    except_set  :REF_TO HSAL_Socket_Set;
	timeout     :REF_TO HSAL_Socket_Time;
END_VAR
END_FUNCTION

TYPE HSAL_Socket_Set:
STRUCT 
	__attrs     : HSAL_Socket_Set_Attrs;  
      clear     :REF_TO typedef_HSAL_Socket_Set_clear;  //void ( *clear)(struct HSAL_Socket_Set *set, HSAL_Socket *socket);
      is_set    :REF_TO typedef_HSAL_Socket_Set_is_set;   //bool ( *is_set)(struct HSAL_Socket_Set *set, HSAL_Socket *socket);
      set       :REF_TO typedef_HSAL_Socket_Set_set;   //void ( *set)(struct HSAL_Socket_Set *set, HSAL_Socket *socket);
      zero      :REF_TO typedef_HSAL_Socket_Set_zero;   //void ( *zero)(struct HSAL_Socket_Set *set);
      select    :REF_TO typedef_HSAL_Socket_Set_select;       //int ( *select)(struct HSAL_Socket_Set *read_set, struct HSAL_Socket_Set *write_set, struct HSAL_Socket_Set *except_set, const HSAL_Socket_Time *timeout); 
END_STRUCT
END_TYPE

/**
 * @brief Конструктор набора сокетов  
 * @param [in] set Описатель набора сокета
 * @return Результат
 * := 0 - Успешное завершение
 * < 0 - Код ошибки
 */
//int hsal_socket_set_constructor(HSAL_Socket_Set *set);
@EXTERNAL FUNCTION hsal_socket_set_constructor : DINT
VAR_INPUT 
	socket      :REF_TO HSAL_Socket_Set;
END_VAR
END_FUNCTION

/*
BSD sockets (+ some network functions)
[+] int accept(int s, struct sockaddr *addr, socklen_t *addrlen);
[+] int bind(int sockfd, struct sockaddr *my_addr, socklen_t addrlen);
[+] int close(int fd);
[+] int connect(int sockfd, const struct sockaddr *serv_addr, socklen_t addrlen);
[-] int gethostname(char *name, size_t len);
[-] int sethostname(const char *name, size_t len);
[+] int getpeername(int s, struct sockaddr *name, socklen_t *namelen);
[+] int getsockname(int s, struct sockaddr *name, socklen_t *namelen);
[+] int getsockopt(int s, int level, int optname, void *optval, socklen_t *optlen);
[+] int listen(int s, int backlog);
[m] int fcntl(int fd, int cmd, long arg);
[-] int ioctl(int d, int request, ...);
[-] int poll(struct pollfd *ufds, unsigned int nfds, int timeout);
[+] const char *inet_ntop(int af, const void *src, char *dst, size_t cnt);
[+] int inet_pton(int af, const char *src, void *dst);
[?] int getaddrinfo(const char *node, const char *service, const struct addrinfo *hints, struct addrinfo **res);
[?] void freeaddrinfo(struct addrinfo *res);
[?] int getnameinfo(const struct sockaddr *sa, socklen_t salen, char *host, size_t hostlen, char *serv, size_t servlen, int flags);
[m] int select(int n, fd_set *readfds, fd_set *writefds, fd_set *exceptfds, struct timeval *timeout);
[+] int recv(int s, void *buf, size_t len, int flags);
[+] int recvfrom(int s, void *buf, size_t len, int flags, struct sockaddr *from, socklen_t *fromlen);
[?] int recvmsg(int s, struct msghdr *msg, int flags);
[+] ssize_t send(int s, const void *msg, size_t len, int flags);
[+] ssize_t sendto(int s, const void *msg, size_t len, int flags, const struct sockaddr *to, socklen_t tolen);
[?] ssize_t sendmsg(int s, const struct msghdr *msg, int flags);
[+] int setsockopt(int s, int level, int optname, const void *optval, socklen_t optlen);
[+] int shutdown(int s, int how);
[-] int sockatmark(int s);
[+] int socket(int domain, int type, int protocol);
[?] int socketpair(int d, int type, int protocol, int sv[2]);
*/


