summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorKaz Kylheku <kaz@kylheku.com>2022-02-17 20:08:16 -0800
committerKaz Kylheku <kaz@kylheku.com>2022-02-17 20:08:16 -0800
commitc27e986b91fe7db72ae87f731be84fec0e9fab53 (patch)
tree9f500b44c2641c997526b1fd659473f3d9951b85
parent42e6aaefb83fafc5338c892006f8189937b0667e (diff)
downloadtxr-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.h2
-rw-r--r--ffi.c132
-rw-r--r--ffi.h9
-rw-r--r--lib.c4
-rw-r--r--socket.c96
5 files changed, 135 insertions, 108 deletions
diff --git a/alloca.h b/alloca.h
index b922c8fe..fd38f81f 100644
--- a/alloca.h
+++ b/alloca.h
@@ -37,3 +37,5 @@
#error portme
#endif
#endif
+
+#define zalloca(size) memset(alloca(size), 0, size)
diff --git a/ffi.c b/ffi.c
index 63fdf45a..8be380b6 100644
--- a/ffi.c
+++ b/ffi.c
@@ -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();
diff --git a/ffi.h b/ffi.h
index 4f206ad9..e44cc51e 100644
--- a/ffi.h
+++ b/ffi.h
@@ -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);
diff --git a/lib.c b/lib.c
index 39faca3e..2a3b7680 100644
--- a/lib.c
+++ b/lib.c
@@ -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();
diff --git a/socket.c b/socket.c
index b161aa75..56f6773c 100644
--- a/socket.c
+++ b/socket.c
@@ -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;