-
Notifications
You must be signed in to change notification settings - Fork 0
/
cmucl.lisp
80 lines (73 loc) · 3.5 KB
/
cmucl.lisp
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
(in-package :trivial-sockets)
(defun resolve-hostname (name)
(cond
((eql name :any) "0.0.0.0")
((typep name '(vector number 4)) (format nil "~{~A~^.~}" (coerce name 'list)))
(t name)))
(defun pretty-stream-name (host port)
(format nil "~A:~A" (resolve-hostname host) port))
(defun open-stream (peer-host peer-port
&key (local-host :any) (local-port 0)
(external-format :default)
(element-type 'character)
(protocol :tcp))
(unless (eql external-format :default)
(error 'unsupported :feature :external-format))
(unless (and (eql local-host :any) (eql local-port 0))
(error 'unsupported :feature :bind))
(unless (member protocol '(:tcp :udp))
(error 'unsupported :feature `(:protocol ,protocol)))
;; connect-to-inet-socket signals simple-erors. not great
(handler-bind ((error (lambda (c) (error 'socket-error :nested-error c))))
(let ((s (ext:connect-to-inet-socket
(resolve-hostname peer-host) peer-port
(case protocol
(:tcp :stream)
(:udp :datagram)))))
(sys:make-fd-stream s :input t :output t :element-type element-type
:buffering :full
:name (pretty-stream-name peer-host peer-port)))))
(defun open-server (&key (host :any) (port 0)
(reuse-address t)
(backlog 1)
(protocol :tcp))
"Returns a SERVER object and the port that was bound, as multiple values"
(unless (member protocol '(:tcp :udp))
(error 'unsupported :feature `(:protocol ,protocol)))
(handler-bind ((error (lambda (c) (error 'socket-error :nested-error c))))
(let ((socket (if (equal (resolve-hostname host) "0.0.0.0")
;; create-inet-listener barfs on `:host nil'
(ext:create-inet-listener port (case protocol
(:tcp :stream)
(:udp :datagram))
:reuse-address reuse-address
:backlog backlog)
(ext:create-inet-listener port (case protocol
(:tcp :stream)
(:udp :datagram))
:reuse-address reuse-address
:backlog backlog
:host host))))
(multiple-value-bind (host port)
(ext:get-socket-host-and-port socket)
(declare (ignore host))
(values socket port)))))
(defun close-server (server)
(unix:unix-close server))
(defun accept-connection (socket
&key
(external-format :default)
(element-type 'character)
(buffering :full)) ; (member :full :line :none)
(unless (eql external-format :default)
(error 'unsupported :feature :external-format))
(handler-bind ((error (lambda (c) (error 'socket-error :nested-error c))))
(let ((fd (ext:accept-tcp-connection socket)))
(multiple-value-bind (peer-host peer-port)
(ext:get-peer-host-and-port fd)
(sys:make-fd-stream fd
:input t :output t
:element-type element-type
:auto-close t
:buffering buffering
:name (pretty-stream-name peer-host peer-port))))))