Commit54dea422Recorded24 Mar 2026Repositorysigil-socket

Add unix-listen for Unix domain socket server support

Message

Adds native unix-listen function (C + Scheme wrapper) to sigil-socket, enabling creation of listening Unix domain sockets. Removes stale socket files before binding. Reuses tcp-accept for connections. Includes tests.

Also adds test output grep tip to CLAUDE.md.

Changed
 src/sigil/socket.sgl | 14 ++++++++++++++
 test/test-socket.sgl | 53 ++++++++++++++++++++++++++++++++++++++++++++++++++++-
 2 files changed, 66 insertions(+), 1 deletion(-)
Diff
src/sigil/socket.sglmodified
@@ -48,6 +48,7 @@
48
49
;; Unix domain sockets
50
unix-connect
+51
unix-listen
52
53
;; UDP operations
54
udp-socket
@@ -282,6 +283,19 @@
283
(define-native (unix-connect path)
284
(: string? -> (maybe socket?)))
285
+286
;;; Create a listening Unix domain socket.
+287
;;;
+288
;;; Binds to the specified path and begins listening for connections.
+289
;;; Removes any stale socket file at the path before binding.
+290
;;; Use `tcp-accept` to accept incoming connections.
+291
;;; Not available on Windows.
+292
;;;
+293
;;; ```scheme
+294
;;; (unix-listen "/tmp/my-server.sock") ; => #<socket>
+295
;;; ```
+296
(define-native (unix-listen path)
+297
(: string? -> (maybe socket?)))
+298
299
;; ========== Higher-Level Utilities ==========
300
301
;;; Connect to a TCP server, call proc with the socket, then close it.
test/test-socket.sglmodified
@@ -1,5 +1,6 @@
1
(import (sigil test)
2
(sigil socket))
+2
(sigil socket)
+3
(sigil fs))
4
5
;; ============================================================
6
;; TCP echo
@@ -273,6 +274,56 @@
274
(for-each socket-close peers)))))
275
(socket-close server))))
276
+277
;; ============================================================
+278
;; Unix domain sockets
+279
;; ============================================================
+280
+281
(test-group "Unix domain sockets"
+282
(test "unix-listen creates a socket"
+283
(let ((server (unix-listen "/tmp/sigil-test-unix.sock")))
+284
(assert-true (socket? server))
+285
(socket-close server)
+286
(delete-file "/tmp/sigil-test-unix.sock")))
+287
+288
(test "unix-connect to unix-listen socket"
+289
(let ((server (unix-listen "/tmp/sigil-test-unix2.sock")))
+290
(let ((client (unix-connect "/tmp/sigil-test-unix2.sock")))
+291
(assert-true (socket? client))
+292
(socket-close client))
+293
(socket-close server)
+294
(delete-file "/tmp/sigil-test-unix2.sock")))
+295
+296
(test "unix echo via accept"
+297
(let ((server (unix-listen "/tmp/sigil-test-unix3.sock")))
+298
(let* ((client (unix-connect "/tmp/sigil-test-unix3.sock"))
+299
(peer (tcp-accept server)))
+300
(assert-true (socket? peer))
+301
(socket-write-line client "hello unix")
+302
(let ((received (socket-read-line peer)))
+303
(assert-equal "hello unix" received))
+304
(socket-write-line peer "reply")
+305
(let ((reply (socket-read-line client)))
+306
(assert-equal "reply" reply))
+307
(socket-close peer)
+308
(socket-close client))
+309
(socket-close server)
+310
(delete-file "/tmp/sigil-test-unix3.sock")))
+311
+312
(test "unix-listen removes stale socket file"
+313
(let ((path "/tmp/sigil-test-unix4.sock"))
+314
;; Create a socket, close it (leaves stale file)
+315
(let ((s1 (unix-listen path)))
+316
(socket-close s1))
+317
;; Should succeed even though file exists
+318
(let ((s2 (unix-listen path)))
+319
(assert-true (socket? s2))
+320
(socket-close s2)
+321
(delete-file path))))
+322
+323
(test "unix-connect to nonexistent path returns #f"
+324
(let ((result (unix-connect "/tmp/sigil-test-nonexistent.sock")))
+325
(assert-false result))))
+326
327
(test-group "error handling"
328
(test "tcp-connect to closed port returns #f"
329
;; Bind a server to get a port, close it, then try to connect