@@ 7,10 7,6 @@
-- c imports
## cinclude '<sys/socket.h>'
-local AF_INET: cint <cimport, nodecl>
-local AF_INET6: cint <cimport, nodecl>
--- local AF_UNIX: cint <cimport, nodecl>
-
local SOCK_STREAM: cint <cimport, nodecl>
-- local SOCK_DGRAM: cint <cimport, nodecl>
-- local SOCK_RAW: cint <cimport, nodecl>
@@ 18,16 14,45 @@ local SOCK_STREAM: cint <cimport, nodecl>
local MSG_DONTWAIT: cint <cimport, nodecl>
local MSG_PEEK: cint <cimport, nodecl>
-local function c_socket(domain: cint, type: cint, protocol: cint): cint <cimport 'socket', nodecl> end
+local c_sa_family_t <cimport 'sa_family_t',cincomplete, nodecl> = @record{}
+local AF_INET: c_sa_family_t <cimport, nodecl>
+local AF_INET6: c_sa_family_t <cimport, nodecl>
+local AF_UNIX: c_sa_family_t <cimport, nodecl>
+
+local in_port_t: type = @uint16
+local in_addr_t: type = @uint32
+local in_addr = @record{
+ s_addr: in_addr_t
+}
+local sockaddr_in <cimport 'struct sockaddr_in', cincomplete, nodecl> = @record{
+ sin_family: c_sa_family_t,
+ sin_port: in_port_t,
+ sin_addr: in_addr
+}
+
+local in6_addr = @record{
+ s6_addr: [16]byte
+}
+local sockaddr_in6 <cimport 'struct sockaddr_in6', cincomplete, nodecl> = @record{
+ sin6_family: c_sa_family_t,
+ sin6_port: in_port_t,
+ sin6_flowinfo: uint32,
+ sin6_addr: in6_addr,
+ sin6_scope_id: uint32
+}
+
+local function c_socket(domain: c_sa_family_t, type: cint, protocol: cint): cint <cimport 'socket', nodecl> end
+local function c_bind(fd: cint, addr: pointer <const>, len: cint): cint <cimport 'bind', nodecl> end
local function c_accept(fd: cint, address: pointer, address_len: *cint): cint <cimport 'accept', nodecl> end
local function c_listen(fd: cint, backlog: cint): cint <cimport 'listen', nodecl> end
+
local function c_send(fd: cint, buf: *[0]byte, len: usize, flags: cint): isize <cimport 'send', nodecl> end
local function c_recv(fd: cint, buf: *[0]byte, len: usize, flags: cint): isize <cimport 'recv', nodecl> end
## cinclude '<arpa/inet.h>'
-local function c_inet_pton(af: cint, src: cstring <const>, dst: pointer): cint <cimport 'inet_pton', nodecl> end
+local function c_inet_pton(af: c_sa_family_t, src: cstring <const>, dst: pointer): cint <cimport 'inet_pton', nodecl> end
local function c_htons(hostshort: uint16): uint16 <cimport 'htons'> end
local function c_ntohs(hostshort: uint16): uint16 <cimport 'ntohs'> end
@@ 80,9 105,7 @@ require 'C.stdio'
require 'allocators.default'
-local function fakeuse(...: varargs) end
-
-local function die_errno(cond: boolean, msg: string): void
+local function die_errno(cond: boolean, msg: string): void <inline>
if cond then
C.perror(nilptr)
error(msg)
@@ 257,29 280,22 @@ local inet6_re = '^{([^}]+)}:(%d?%d?%d?%d?%d)$'
function export.listen_tcp(address: string, conn_cap: uinteger, handler: function(): void): void
local matched, matches
if (do matched, matches = address:match(inet_re); in matched end) then
- local c_err: cint = 0
-
- local s_addr, s_port = matches:unpack(1, 2)
- local addr: uint32
- die_errno(c_inet_pton(AF_INET, (@cstring)(s_addr), &addr) <= 0,
+ local addr, port = matches:unpack(1, 2)
+ local p_addr: uint32
+ die_errno(c_inet_pton(AF_INET, (@cstring)(addr), &p_addr) <= 0,
"bad IPv4 address")
- local i_port = tointeger(s_port)
- assert((i_port >= 0) and (i_port < 65535), "port not within range [0,65536)")
- local port: uint16 = c_htons(i_port)
+ local port = tointeger(port)
+ assert((port >= 0) and (port < 65535), "port not within range [0,65536)")
+ local port: uint16 = c_htons(port)
local fd = c_socket(AF_INET, SOCK_STREAM, 0)
die_errno(fd == -1, "couldn't open TCP socket")
- fakeuse(port)
- ##[==[ cemit [[
- struct sockaddr_in sa;
- memset(&sa, 0, sizeof(sa));
- sa.sin_family = AF_INET;
- sa.sin_port = port;
- sa.sin_addr.s_addr = addr;
- c_err = bind(fd, &sa, sizeof(sa));
- ]] ]==]
- die_errno(c_err == -1, "couldn't bind TCP socket")
+ local sa: sockaddr_in
+ sa.sin_family = AF_INET
+ sa.sin_port = port
+ sa.sin_addr.s_addr = p_addr
+ die_errno(c_bind(fd, &sa, #(@sockaddr_in)) == -1, "couldn't bind TCP socket")
defer c_close(fd) end
@@ 287,31 303,28 @@ function export.listen_tcp(address: string, conn_cap: uinteger, handler: functio
elseif (do matched, matches = address:match(inet6_re); in matched end) then
local c_err: cint = 0
- local s_addr, s_port = matches:unpack(1, 2)
- local addr: [16]byte
- die_errno(c_inet_pton(AF_INET6, (@cstring)(s_addr), &addr) <= 0,
+ local addr, port = matches:unpack(1, 2)
+ local p_addr: [16]byte
+ die_errno(c_inet_pton(AF_INET6, (@cstring)(addr), &p_addr) <= 0,
"bad IPv6 address")
- local i_port = tointeger(s_port)
- assert((i_port >= 0) and (i_port < 65535), "port not within range [0,65536)")
- local port: uint16 = c_htons(i_port)
+ local port = tointeger(port)
+ assert((port >= 0) and (port < 65535), "port not within range [0,65536)")
+ local port: uint16 = c_htons(port)
local fd = c_socket(AF_INET6, SOCK_STREAM, 0)
die_errno(fd == -1, "couldn't open TCP socket")
- fakeuse(port)
- ##[==[ cemit [[
- struct sockaddr_in6 sa;
- memset(&sa, 0, sizeof(sa));
- sa.sin6_family = AF_INET6;
- sa.sin6_port = port;
- memcpy(&sa.sin6_addr.s6_addr, &addr, sizeof(addr));
- c_err = bind(fd, &sa, sizeof(sa));
- ]] ]==]
- die_errno(c_err == -1, "couldn't bind TCP socket")
+ local sa: sockaddr_in6
+ sa.sin6_family = AF_INET6
+ sa.sin6_port = port
+ sa.sin6_addr.s6_addr = p_addr
+ die_errno(c_bind(fd, &sa, #(@sockaddr_in6)) == -1, "couldn't bind TCP socket")
defer c_close(fd) end
export.listen_sock(fd, conn_cap, handler)
+ else
+ error("bad addr: "..address)
end
end