diff options
author | Kaz Kylheku <kaz@kylheku.com> | 2022-02-17 20:08:16 -0800 |
---|---|---|
committer | Kaz Kylheku <kaz@kylheku.com> | 2022-02-17 20:08:16 -0800 |
commit | c27e986b91fe7db72ae87f731be84fec0e9fab53 (patch) | |
tree | 9f500b44c2641c997526b1fd659473f3d9951b85 | |
parent | 42e6aaefb83fafc5338c892006f8189937b0667e (diff) | |
download | txr-c27e986b91fe7db72ae87f731be84fec0e9fab53.tar.gz txr-c27e986b91fe7db72ae87f731be84fec0e9fab53.tar.bz2 txr-c27e986b91fe7db72ae87f731be84fec0e9fab53.zip |
ffi: move socket stuff to socket module.
* alloca.h (zalloca): Macro moved here from ffi.c; it's useful
to any code that wants to do a zero-filled alloca, and
socket.c needs it now.
* ffi.c (HAVE_SOCKETS): All includes conditional on HAVE_SOCKETS
removed.
(zalloca): Macro removed; moved to alloca.h.
(ffi_type_struct_checked, ffi_type_lookup): Static functions
changed to external linkage.
(ffi_type_size, ffi_type_put, ffi_type_get): New functions,
used by external module that has incomplete definition of
struct txr_ffi_type.
(type_by_size): New static array, moved out of
ffi_init_extra_types function.
(ffi_type_by_size): New function.
(ffi_init_extra_types): type_by_size array relocated to
file scope.
(sock_opt, sock_set_opt): Moved to socket.c, and adjusted to
use newly developed external access to needed ffi mechanisms.
(ffi_init): Numerous definitions related to sockets removed;
these go to socket.c.
* ffi.h (struct txr_ffi_type): Declared here now as
incomplete type.
(ffi_type_struct_checked, ffi_type_size, ffi_type_put,
ffi_type_get, ffi_type_lookup, ffi_type_by_size): Declared.
* lib.c (init): Call new function sock_init.
* socket.c (sock_opt, sock_set_opt): New functions, moved
from ffi.c, and slightly adapted to work with external
interfaces exposed by ffi.c.
(sock_init): New function. This performs unconditional
initializations not keyed to the lazy loading lisplib.c
mechanism. Here we create the socklen-t FFI type.
FFI types lookup doesn't trigger lazy loading, so we do it
this way; the alternative would be to introduce lazy load
triggering to FFI type lookup, just for this one type.
(sock_load_init): All the socket function and variable
registrations move here from ffi_init.
-rw-r--r-- | alloca.h | 2 | ||||
-rw-r--r-- | ffi.c | 132 | ||||
-rw-r--r-- | ffi.h | 9 | ||||
-rw-r--r-- | lib.c | 4 | ||||
-rw-r--r-- | socket.c | 96 |
5 files changed, 135 insertions, 108 deletions
@@ -37,3 +37,5 @@ #error portme #endif #endif + +#define zalloca(size) memset(alloca(size), 0, size) @@ -44,11 +44,6 @@ #if HAVE_SYS_TYPES_H #include <sys/types.h> #endif -#if HAVE_SOCKETS -#include <sys/socket.h> -#include <netinet/in.h> -#include <netinet/tcp.h> -#endif #if HAVE_MMAP #include <sys/mman.h> #include <unistd.h> @@ -75,8 +70,6 @@ #include "ffi.h" #include "txr.h" -#define zalloca(size) memset(alloca(size), 0, size) - #define alignof(type) offsetof(struct {char x; type y;}, y) #define pad_retval(size) (!(size) || convert(size_t, size) > sizeof (ffi_arg) \ @@ -239,7 +232,7 @@ static struct txr_ffi_type *ffi_type_struct(val obj) return coerce(struct txr_ffi_type *, obj->co.handle); } -static struct txr_ffi_type *ffi_type_struct_checked(val self, val obj) +struct txr_ffi_type *ffi_type_struct_checked(val self, val obj) { return coerce(struct txr_ffi_type *, cobj_handle(self, obj, ffi_type_cls)); } @@ -359,6 +352,21 @@ static struct cobj_ops ffi_type_enum_ops = ffi_enum_type_mark, cobj_eq_hash_op); +cnum ffi_type_size(struct txr_ffi_type *tft) +{ + return tft->size; +} + +void ffi_type_put(struct txr_ffi_type *tft, val obj, mem_t *dst, val self) +{ + tft->put(tft, obj, dst, self); +} + +val ffi_type_get(struct txr_ffi_type *tft, mem_t *src, val self) +{ + return tft->get(tft, src, self); +} + #if HAVE_LIBFFI struct txr_ffi_closure { @@ -3728,7 +3736,7 @@ static val make_ffi_type_enum(val syntax, val enums, return type_copy; } -static val ffi_type_lookup(val sym) +val ffi_type_lookup(val sym) { return gethash(ffi_typedef_hash, sym); } @@ -4640,10 +4648,15 @@ static void ffi_init_types(void) ffi_typedef(bool_s, ffi_type_compile(cons(bool_s, cons(uchar_s, nil)))); } -static void ffi_init_extra_types(void) +static val type_by_size[2][16]; + +val ffi_type_by_size(int unsig, size_t size) { - val type_by_size[2][18] = { { 0 }, { 0 } }; + return type_by_size[unsig][size]; +} +static void ffi_init_extra_types(void) +{ #if HAVE_I64 type_by_size[0][sizeof (i64_t)] = ffi_type_lookup(int64_s); type_by_size[1][sizeof (i64_t)] = ffi_type_lookup(uint64_s); @@ -4730,11 +4743,6 @@ static void ffi_init_extra_types(void) type_by_size[convert(uid_t, -1) > 0][sizeof (uid_t)]); #endif -#if HAVE_SOCKETS - ffi_typedef(intern(lit("socklen-t"), user_package), - type_by_size[convert(socklen_t, -1) > 0][sizeof (socklen_t)]); -#endif - ffi_typedef(intern(lit("longlong"), user_package), type_by_size[0][sizeof (long long)]); ffi_typedef(intern(lit("ulonglong"), user_package), @@ -6698,65 +6706,6 @@ static val dyn_size(val type, val obj) return num(tft->dynsize(tft, obj, self)); } -#if HAVE_SOCKETS - -static val sock_opt(val sock, val level, val option, val type_opt) -{ - val self = lit("sock-opt"); - val sfd = stream_fd(sock); - int lvl = c_int(level, self); - int opt = c_int(option, self); - val type = default_arg(type_opt, ffi_type_lookup(int_s)); - struct txr_ffi_type *tft = ffi_type_struct_checked(self, type); - - if (!sfd) { - uw_throwf(socket_error_s, lit("~a: cannot get option on ~s"), - self, sock, nao); - } else { - socklen_t size = convert(socklen_t, tft->size); - mem_t *data = coerce(mem_t *, zalloca(size)); - if (getsockopt(c_num(sfd, self), lvl, opt, data, &size) != 0) - uw_ethrowf(socket_error_s, lit("~a failed on ~s: ~d/~s"), - self, sock, num(errno), errno_to_str(errno), nao); - /* TODO: Add a separate function to handle options with - * variable-size values, for example the platform-specific - * SO_BINDTODEVICE. - * (Or perhaps add an optional argument following type_opt - * specifying the requested length of the value, presumably of type - * carray.) */ - if (size != convert(socklen_t, tft->size)) - uw_throwf(socket_error_s, lit("~a: variable-size option on ~s"), - self, sock, nao); - return tft->get(tft, data, self); - } -} - -static val sock_set_opt(val sock, val level, val option, val value, - val type_opt) -{ - val self = lit("sock-set-opt"); - val sfd = stream_fd(sock); - int lvl = c_int(level, self); - int opt = c_int(option, self); - val type = default_arg(type_opt, ffi_type_lookup(int_s)); - struct txr_ffi_type *tft = ffi_type_struct_checked(self, type); - - if (!sfd) { - uw_throwf(socket_error_s, lit("~a: cannot set option on ~s"), - self, sock, nao); - } else { - socklen_t size = convert(socklen_t, tft->size); - mem_t *data = coerce(mem_t *, zalloca(size)); - tft->put(tft, value, data, self); - if (setsockopt(c_num(sfd, self), lvl, opt, data, size) != 0) - uw_ethrowf(socket_error_s, lit("~a failed on ~s: ~d/~s"), - self, sock, num(errno), errno_to_str(errno), nao); - return value; - } -} - -#endif - void ffi_init(void) { prot1(&ffi_typedef_hash); @@ -6954,39 +6903,6 @@ void ffi_init(void) reg_fun(intern(lit("get-obj"), user_package), func_n2o(get_obj, 1)); reg_fun(intern(lit("fill-obj"), user_package), func_n3o(fill_obj, 2)); reg_fun(intern(lit("dyn-size"), system_package), func_n2(dyn_size)); -#if HAVE_SOCKETS - reg_fun(intern(lit("sock-opt"), user_package), func_n4o(sock_opt, 3)); - reg_fun(intern(lit("sock-set-opt"), user_package), func_n5o(sock_set_opt, 4)); - reg_varl(intern(lit("sol-socket"), user_package), num_fast(SOL_SOCKET)); - reg_varl(intern(lit("ipproto-ip"), user_package), num_fast(IPPROTO_IP)); - reg_varl(intern(lit("ipproto-ipv6"), user_package), num_fast(IPPROTO_IPV6)); - reg_varl(intern(lit("ipproto-tcp"), user_package), num_fast(IPPROTO_TCP)); - reg_varl(intern(lit("ipproto-udp"), user_package), num_fast(IPPROTO_UDP)); - reg_varl(intern(lit("so-acceptconn"), user_package), num_fast(SO_ACCEPTCONN)); - reg_varl(intern(lit("so-broadcast"), user_package), num_fast(SO_BROADCAST)); - reg_varl(intern(lit("so-debug"), user_package), num_fast(SO_DEBUG)); - reg_varl(intern(lit("so-dontroute"), user_package), num_fast(SO_DONTROUTE)); - reg_varl(intern(lit("so-error"), user_package), num_fast(SO_ERROR)); - reg_varl(intern(lit("so-keepalive"), user_package), num_fast(SO_KEEPALIVE)); - reg_varl(intern(lit("so-linger"), user_package), num_fast(SO_LINGER)); - reg_varl(intern(lit("so-oobinline"), user_package), num_fast(SO_OOBINLINE)); - reg_varl(intern(lit("so-rcvbuf"), user_package), num_fast(SO_RCVBUF)); - reg_varl(intern(lit("so-rcvlowat"), user_package), num_fast(SO_RCVLOWAT)); - reg_varl(intern(lit("so-rcvtimeo"), user_package), num_fast(SO_RCVTIMEO)); - reg_varl(intern(lit("so-reuseaddr"), user_package), num_fast(SO_REUSEADDR)); - reg_varl(intern(lit("so-sndbuf"), user_package), num_fast(SO_SNDBUF)); - reg_varl(intern(lit("so-sndlowat"), user_package), num_fast(SO_SNDLOWAT)); - reg_varl(intern(lit("so-sndtimeo"), user_package), num_fast(SO_SNDTIMEO)); - reg_varl(intern(lit("so-type"), user_package), num_fast(SO_TYPE)); - reg_varl(intern(lit("ipv6-join-group"), user_package), num_fast(IPV6_JOIN_GROUP)); - reg_varl(intern(lit("ipv6-leave-group"), user_package), num_fast(IPV6_LEAVE_GROUP)); - reg_varl(intern(lit("ipv6-multicast-hops"), user_package), num_fast(IPV6_MULTICAST_HOPS)); - reg_varl(intern(lit("ipv6-multicast-if"), user_package), num_fast(IPV6_MULTICAST_IF)); - reg_varl(intern(lit("ipv6-multicast-loop"), user_package), num_fast(IPV6_MULTICAST_LOOP)); - reg_varl(intern(lit("ipv6-unicast-hops"), user_package), num_fast(IPV6_UNICAST_HOPS)); - reg_varl(intern(lit("ipv6-v6only"), user_package), num_fast(IPV6_V6ONLY)); - reg_varl(intern(lit("tcp-nodelay"), user_package), num_fast(TCP_NODELAY)); -#endif ffi_typedef_hash = make_hash(hash_weak_none, nil); ffi_struct_tag_hash = make_hash(hash_weak_none, nil); ffi_init_types(); @@ -26,6 +26,8 @@ * POSSIBILITY OF SUCH DAMAGE. */ +struct txr_ffi_type; + extern val uint8_s, int8_s; extern val uint16_s, int16_s; extern val uint32_s, int32_s; @@ -74,7 +76,13 @@ extern val ffi_type_s, ffi_call_desc_s, ffi_closure_s; extern struct cobj_class *carray_cls; +struct txr_ffi_type *ffi_type_struct_checked(val self, val typeobj); +cnum ffi_type_size(struct txr_ffi_type *); +void ffi_type_put(struct txr_ffi_type *, val obj, mem_t *dst, val self); +val ffi_type_get(struct txr_ffi_type *, mem_t *src, val self); + val ffi_type_compile(val syntax); +val ffi_type_lookup(val sym); val ffi_type_operator_p(val sym); val ffi_type_p(val sym); val ffi_make_call_desc(val ntotal, val nfixed, val rettype, val argtypes, @@ -151,5 +159,6 @@ val zero_fill(val type, val obj); val put_obj(val obj, val type, val stream); val get_obj(val type, val stream); val fill_obj(val obj, val type, val stream); +val ffi_type_by_size(int unsig, size_t size); void ffi_init(void); void ffi_compat_fixup(int compat_ver); @@ -77,6 +77,7 @@ #include "buf.h" #include "ffi.h" #include "chksum.h" +#include "socket.h" #include "txr.h" #include "debug.h" @@ -14434,6 +14435,9 @@ void init(val *stack_bottom) cadr_init(); time_init(); chksum_init(); +#if HAVE_SOCKETS + sock_init(); +#endif cobj_populate_hash(); @@ -50,6 +50,7 @@ #include <sys/time.h> #endif #include <netinet/in.h> +#include <netinet/tcp.h> #include "lib.h" #include "stream.h" #include "signal.h" @@ -61,6 +62,8 @@ #include "struct.h" #include "arith.h" #include "sysif.h" +#include "itypes.h" +#include "ffi.h" #include "socket.h" #define MIN(A, B) ((A) < (B) ? (A) : (B)) @@ -1153,6 +1156,68 @@ static val socketpair_wrap(val family, val type, val mode_str) return out; } +static val sock_opt(val sock, val level, val option, val type_opt) +{ + val self = lit("sock-opt"); + val sfd = stream_fd(sock); + int lvl = c_int(level, self); + int opt = c_int(option, self); + val type = default_arg(type_opt, ffi_type_lookup(int_s)); + struct txr_ffi_type *tft = ffi_type_struct_checked(self, type); + + if (!sfd) { + uw_throwf(socket_error_s, lit("~a: cannot get option on ~s"), + self, sock, nao); + } else { + socklen_t typesize = convert(socklen_t, ffi_type_size(tft)); + socklen_t size = typesize; + mem_t *data = coerce(mem_t *, zalloca(size)); + if (getsockopt(c_num(sfd, self), lvl, opt, data, &size) != 0) + uw_ethrowf(socket_error_s, lit("~a failed on ~s: ~d/~s"), + self, sock, num(errno), errno_to_str(errno), nao); + /* TODO: Add a separate function to handle options with + * variable-size values, for example the platform-specific + * SO_BINDTODEVICE. + * (Or perhaps add an optional argument following type_opt + * specifying the requested length of the value, presumably of type + * carray.) */ + if (size != typesize) + uw_throwf(socket_error_s, lit("~a: variable-size option on ~s"), + self, sock, nao); + return ffi_type_get(tft, data, self); + } +} + +static val sock_set_opt(val sock, val level, val option, val value, + val type_opt) +{ + val self = lit("sock-set-opt"); + val sfd = stream_fd(sock); + int lvl = c_int(level, self); + int opt = c_int(option, self); + val type = default_arg(type_opt, ffi_type_lookup(int_s)); + struct txr_ffi_type *tft = ffi_type_struct_checked(self, type); + + if (!sfd) { + uw_throwf(socket_error_s, lit("~a: cannot set option on ~s"), + self, sock, nao); + } else { + socklen_t size = convert(socklen_t, ffi_type_size(tft)); + mem_t *data = coerce(mem_t *, zalloca(size)); + ffi_type_put(tft, value, data, self); + if (setsockopt(c_num(sfd, self), lvl, opt, data, size) != 0) + uw_ethrowf(socket_error_s, lit("~a failed on ~s: ~d/~s"), + self, sock, num(errno), errno_to_str(errno), nao); + return value; + } +} + +void sock_init(void) +{ + ffi_typedef(intern(lit("socklen-t"), user_package), + ffi_type_by_size(convert(socklen_t, -1) > 0, sizeof (socklen_t))); +} + void sock_load_init(void) { sockaddr_in_s = intern(lit("sockaddr-in"), user_package); @@ -1217,6 +1282,37 @@ void sock_load_init(void) reg_fun(intern(lit("sock-send-timeout"), user_package), func_n2(sock_send_timeout)); reg_fun(intern(lit("sock-recv-timeout"), user_package), func_n2(sock_recv_timeout)); #endif + reg_fun(intern(lit("sock-opt"), user_package), func_n4o(sock_opt, 3)); + reg_fun(intern(lit("sock-set-opt"), user_package), func_n5o(sock_set_opt, 4)); + reg_varl(intern(lit("sol-socket"), user_package), num_fast(SOL_SOCKET)); + reg_varl(intern(lit("ipproto-ip"), user_package), num_fast(IPPROTO_IP)); + reg_varl(intern(lit("ipproto-ipv6"), user_package), num_fast(IPPROTO_IPV6)); + reg_varl(intern(lit("ipproto-tcp"), user_package), num_fast(IPPROTO_TCP)); + reg_varl(intern(lit("ipproto-udp"), user_package), num_fast(IPPROTO_UDP)); + reg_varl(intern(lit("so-acceptconn"), user_package), num_fast(SO_ACCEPTCONN)); + reg_varl(intern(lit("so-broadcast"), user_package), num_fast(SO_BROADCAST)); + reg_varl(intern(lit("so-debug"), user_package), num_fast(SO_DEBUG)); + reg_varl(intern(lit("so-dontroute"), user_package), num_fast(SO_DONTROUTE)); + reg_varl(intern(lit("so-error"), user_package), num_fast(SO_ERROR)); + reg_varl(intern(lit("so-keepalive"), user_package), num_fast(SO_KEEPALIVE)); + reg_varl(intern(lit("so-linger"), user_package), num_fast(SO_LINGER)); + reg_varl(intern(lit("so-oobinline"), user_package), num_fast(SO_OOBINLINE)); + reg_varl(intern(lit("so-rcvbuf"), user_package), num_fast(SO_RCVBUF)); + reg_varl(intern(lit("so-rcvlowat"), user_package), num_fast(SO_RCVLOWAT)); + reg_varl(intern(lit("so-rcvtimeo"), user_package), num_fast(SO_RCVTIMEO)); + reg_varl(intern(lit("so-reuseaddr"), user_package), num_fast(SO_REUSEADDR)); + reg_varl(intern(lit("so-sndbuf"), user_package), num_fast(SO_SNDBUF)); + reg_varl(intern(lit("so-sndlowat"), user_package), num_fast(SO_SNDLOWAT)); + reg_varl(intern(lit("so-sndtimeo"), user_package), num_fast(SO_SNDTIMEO)); + reg_varl(intern(lit("so-type"), user_package), num_fast(SO_TYPE)); + reg_varl(intern(lit("ipv6-join-group"), user_package), num_fast(IPV6_JOIN_GROUP)); + reg_varl(intern(lit("ipv6-leave-group"), user_package), num_fast(IPV6_LEAVE_GROUP)); + reg_varl(intern(lit("ipv6-multicast-hops"), user_package), num_fast(IPV6_MULTICAST_HOPS)); + reg_varl(intern(lit("ipv6-multicast-if"), user_package), num_fast(IPV6_MULTICAST_IF)); + reg_varl(intern(lit("ipv6-multicast-loop"), user_package), num_fast(IPV6_MULTICAST_LOOP)); + reg_varl(intern(lit("ipv6-unicast-hops"), user_package), num_fast(IPV6_UNICAST_HOPS)); + reg_varl(intern(lit("ipv6-v6only"), user_package), num_fast(IPV6_V6ONLY)); + reg_varl(intern(lit("tcp-nodelay"), user_package), num_fast(TCP_NODELAY)); fill_stream_ops(&dgram_strm_ops); dgram_strm_ops.get_sock_family = dgram_get_sock_family; |