File: sock.lsp

package info (click to toggle)
xlispstat 3.52.0-3
  • links: PTS
  • area: main
  • in suites: hamm, slink
  • size: 7,472 kB
  • ctags: 12,480
  • sloc: ansic: 89,534; lisp: 21,690; sh: 1,525; makefile: 520; csh: 1
file content (118 lines) | stat: -rw-r--r-- 4,228 bytes parent folder | download
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
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
(defpackage "SOCKETS" (:use "COMMON-LISP"))
(in-package "SOCKETS")
(shlib::load-shared-library (merge-pathnames "xlsock.dll" *load-pathname*))

(export '(with-client-socket socket-read-line socket-write-line
         socket-force-output socket-write-string
         with-server-socket-loop))

(defstruct (socket (:constructor (make-socket (fd))))
  fd (inbuf (make-string 1024)) (instart 0) (inend 0) ineof)

(defun close-socket (sock)
  (let ((fd (socket-fd sock)))
    (when fd (sock-close fd) (setf (socket-fd sock) nil))
    nil))

(defmacro with-client-socket ((sock host port) &rest body)
  (let ((fdsym (gensym)))
    `(let ((,fdsym (sock-connect ,host ,port)))
       (unless ,fdsym (error "Unable to establish an Internet connection"))
       (let ((,sock (make-socket ,fdsym)))
         (unwind-protect
             (progn ,@body)
           (close-socket ,sock))))))

(defun run-server-loop (port fun fork)
  (let ((listenfd (sock-open port)))
    (unless listenfd (error "Unable to establish a port connection"))
    (unwind-protect
        (loop
         (let ((communfd (sock-listen listenfd)))
           (unless communfd (error "Failure to listen on server"))
           (let ((sock (make-socket communfd)))
             (if fork
                 (let ((pid (fork)))
                   (unless pid "error failure to fork")
                   (case pid
                         (0 (handle-connection sock fun) (exit))
                         (otherwise (close-socket sock))))
               (handle-connection sock fun)))))
      (sock-close listenfd))))

(defun handle-connection (sock fun)
  (unwind-protect
      (funcall fun sock)
    (close-socket sock)))

(defmacro with-server-socket-loop ((sock port &key fork) &rest body)
  `(run-server-loop ,port #'(lambda (,sock) ,@body) ,fork))

(defun socket-write-string (str sock &optional start end)
  (unless start (setf start 0))
  (unless end (setf end (length str)))
  (let ((fd (socket-fd sock)))
    (loop
     (when (<= end start) (return str))
     (let ((count (base-sock-write fd str start end)))
       (unless count (error "socket write failed after ~d bytes" start))
       (incf start count)))))

(defun socket-write-line (str sock &optional start end)
  (socket-write-string str sock start end)
  (socket-write-string "\r\n" sock start end))

(defun socket-force-output (sock) nil)

(defun base-sock-read-char (sock &optional eoferrp eofval recp)
  (if (socket-ineof sock)
      (if eoferrp
          (error "end of file")
        eofval)
    (let ((start (socket-instart sock))
          (end (socket-inend sock)))
      (if (<= end start)
          (let ((count (base-sock-read (socket-fd sock) (socket-inbuf sock))))
            (unless count (error "socket read error"))
            (if (= count 0)
                (setf (socket-ineof sock) t)
              (setf (socket-instart sock) 0
                    (socket-inend sock) count))
            (base-sock-read-char sock eoferrp eofval recp))
        (let ((ch (char (socket-inbuf sock) start)))
          (setf (socket-instart sock) (+ start 1))
          ch)))))

(defun base-sock-peek-char (type sock &optional eoferrp eofval recp)
  (let ((ch (base-sock-read-char sock eoferrp eofval recp)))
    (decf (socket-instart sock))
    ch))

(defun socket-read-char (sock &optional eoferrp eofval recp)
  (let ((ch (base-sock-read-char sock eoferrp eofval recp)))
    (if (eql ch #\return)
        (let ((next (base-sock-peek-char nil sock nil nil)))
          (cond
           ((eql next #\newline) (base-sock-read-char sock) #\newline)
           (t #\return)))
      ch)))

(defun socket-read-byte (sock &optional eoferrp eofval)
  (let ((ch (base-sock-read-char sock eoferrp nil)))
    (if ch
        (char-int ch)
      eofval)))

(defun socket-read-line (sock &optional eoferrp eofval recp)
  (let ((ch (socket-read-char sock eoferrp nil recp))
        (nlmissing nil))
    (if ch
        (values
         (with-output-to-string (s)
           (loop
            (when (null ch) (setf nlmissing t) (return))
            (when (eql ch #\newline) (return))
            (write-char ch s)
            (setf ch (socket-read-char sock nil nil))))
         nlmissing)
      (values eofval t))))