import win32;
public import win32.(
    SOCKET_ERROR,
    socket, bind, listen, accept, connect, send, recv, sendto, recvfrom,
    select, gethostbyname, getsockopt, setsockopt,
    gethostbyaddr,
    AF_UNSPEC, AF_INET, AF_INET6,
    PF_UNSPEC, PF_INET, PF_INET6,
    INADDR_ANY, INADDR_BROADCAST, INADDR_LOOPBACK, INADDR_NONE,
    INADDR_UNSPEC_GROUP, INADDR_ALLHOSTS_GROUP, INADDR_ALLRTRS_GROUP,
    INADDR_MAX_LOCAL_GROUP,
    SOCK_STREAM, SOCK_DGRAM, SOCK_RAW,
    IPPROTO_ICMP, IPPROTO_IGMP, IPPROTO_TCP, IPPROTO_UDP, IPPROTO_ICMPV6,
    SOL_SOCKET,
    SO_REUSEADDR
);

// winsock uses 'char*' and 'int' for buffer pointers and sizes, posix uses 'void*' and 'size_t'
alias DataPointer = Pointer[CChar];
alias DataSize = Int;

alias RawSocket = win32.SOCKET;
alias errno = win32.WSAGetLastError;

alias close = win32.closesocket;

record WSAStartupError(code: Int);
instance Exception (WSAStartupError);
record WSAStartupVersionError();
instance Exception (WSAStartupVersionError);

startSockets() {
    var wsaData = win32.WSADATA();
    var err = win32.WSAStartup(0x0202us, &wsaData);
    if (err == -1)
        throw WSAStartupError(win32.WSAGetLastError());
    if (wsaData.wVersion != 0x0202us) {
        win32.WSACleanup();
        throw WSAStartupVersionError();
    }
}
finishSockets() {
    win32.WSACleanup();
}

alias Sockaddr = win32.Struct_sockaddr;
alias Sockaddr_in = win32.Struct_sockaddr_in;
alias Sockaddr_storage = win32.Struct_sockaddr_storage;
alias In_addr = win32.Struct_in_addr;

s_addr(inaddr:In_addr) = ref bitcast(inaddr, UInt32);

alias SocklenT = Int;
