Annotation of 43BSDReno/contrib/emacs-18.55/dist-1.3/fi/ipc.cl, revision 1.1.1.1

1.1       root        1: ;;                                     -[Mon Nov 28 13:35:34 1988 by layer]-
                      2: ;;
                      3: ;; Allegro CL IPC interface
                      4: ;;
                      5: ;; copyright (c) 1987, 1988 Franz Inc, Berkeley, Ca.
                      6: ;;
                      7: ;; The software, data and information contained herein are proprietary
                      8: ;; to, and comprise valuable trade secrets of, Franz, Inc.  They are
                      9: ;; given in confidence by Franz, Inc. pursuant to a written license
                     10: ;; agreement, and stored only in accordance with the terms of such license.
                     11: ;;
                     12: ;; Restricted Rights Legend
                     13: ;; ------------------------
                     14: ;; Use, duplication, and disclosure by the Government are subject to
                     15: ;; restrictions of Restricted Rights for Commercial Software developed
                     16: ;; at private expense as specified in DOD FAR 52.227-7013 (c) (1) (ii).
                     17: ;;
                     18: ;;
                     19: ;; $Header: ipc.cl,v 1.20 89/02/14 17:14:34 layer Exp $
                     20: ;; $Locker:  $
                     21: ;;
                     22: ;; This code is a preliminary IPC interface for ExCL. The functionality
                     23: ;; will be extended apace, but right now it only implements a Common Lisp
                     24: ;; Server.  The server can be started by a CL and it establishes a daemon
                     25: ;; listening to a socket.  Any process wanting to talk to the lisp
                     26: ;; can connect to the socket and a new Lisp Listener will be started.
                     27: 
                     28: (provide :ipc)
                     29: 
                     30: (in-package :ipc :use '(:lisp :excl :ff :mp))
                     31: 
                     32: (export '(start-lisp-listener-daemon open-network-stream
                     33:          *unix-domain* *inet-port*))
                     34: 
                     35: (require :process)
                     36: (require :foreign)
                     37: (require :cstructs)
                     38: 
                     39: (defvar *unix-domain* t
                     40:   "If non-nil then use a UNIX domain socket, otherwise use an internet
                     41: domain port (see *inet-port* variable).")
                     42: 
                     43: (defparameter *inet-port* 6789
                     44:   "The internet service port number on which Lisp listens for connections.
                     45: The value is this variable is only used when *unix-domain* is non-nil, in
                     46: which case a UNIX domain socket is used.")
                     47: 
                     48: (defconstant *af-unix* 1
                     49:   "The AF_UNIX constant from /usr/include/sys/socket.h.")
                     50: 
                     51: (defconstant *af-inet* 2
                     52:   "The AF_INET constant from /usr/include/sys/socket.h.")
                     53: 
                     54: (defconstant *sock-stream* 1
                     55:   "The SOCK_STREAM constant from /usr/include/sys/socket.h.")
                     56: 
                     57: (defvar *junk-name* (make-array 1))
                     58: (defvar *junk-address* (make-array 1 :element-type '(unsigned-byte 32)))
                     59: 
                     60: (defun entry-point-exists-p (string)
                     61:   (setf (aref *junk-name* 0) string)
                     62:   (setf (aref *junk-address* 0) 0)
                     63:   (= 0 (get-entry-points *junk-name* *junk-address*)))
                     64: 
                     65: (defvar lisp-listener-daemon-ff-loaded nil)
                     66: (defvar lisp-listener-daemon nil)
                     67: 
                     68: (defparameter *needed-funcs*
                     69:   (mapcar #'convert-to-lang
                     70:          '("socket" "bind" "listen" "accept" "getsockname" "gethostbyname"
                     71:            "connect" "bcopy" "bcmp" "bzero")))
                     72: 
                     73: (eval-when (load eval)
                     74:   (unless lisp-listener-daemon-ff-loaded
                     75:     (unless (eql (excl::machine-code) '#.comp::machine-code-tek4300)
                     76:       (unless (or (eq '#.comp::machine-code-apollo (excl::machine-code))
                     77:                  (dolist (name *needed-funcs* t)
                     78:                    (if (not (entry-point-exists-p name))
                     79:                        (return nil))))
                     80:        (princ ";  Loading from C library...")
                     81:        (force-output)
                     82:        (unless (load "" :verbose nil :unreferenced-lib-names *needed-funcs*)
                     83:          (error "foreign load failed"))
                     84:        (princ "done")
                     85:        (terpri)))
                     86:     (setq lisp-listener-daemon-ff-loaded t)
                     87:     (defforeign-list '((getuid) (socket) (bind) (accept)
                     88:                       (getsockname) (gethostbyname) (select)
                     89:                       (connect) (bcopy) (bzero) (bcmp) (perror)
                     90:                       (unix-listen :entry-point #,(convert-to-lang "listen"))
                     91:                       (unix-close :entry-point #,(convert-to-lang "close")))
                     92:        :print nil)))
                     93: 
                     94: (defcstruct sockaddr-in
                     95:   (family :unsigned-short)
                     96:   (port :unsigned-short)
                     97:   (addr :unsigned-long)
                     98:   (zero 8 :unsigned-byte))
                     99: 
                    100: (defcstruct sockaddr-un
                    101:   (family :unsigned-short)
                    102:   (path 109 :char))
                    103: 
                    104: (defcstruct timeval
                    105:   (sec :long)
                    106:   (usec :long))
                    107: 
                    108: (defcstruct unsigned-long
                    109:   (unsigned-long :unsigned-long))
                    110: 
                    111: ;; from /usr/include/netdb.h
                    112: (defcstruct (hostent :malloc)
                    113:   (name * :char)
                    114:   (aliases * * :char)
                    115:   (addrtype :long)
                    116:   (length :long)
                    117:   (addr * :char))
                    118: 
                    119: (defun start-lisp-listener-daemon ()
                    120:   "This function starts a process which listens to a socket for attempts to
                    121: connect, and starts a lisp listener for each connection.  If the Lisp
                    122: listener ever completes, it makes sure files are closed."
                    123:   (unless lisp-listener-daemon
                    124:     (setq lisp-listener-daemon
                    125:       (process-run-function "TCP Listener Socket Daemon"
                    126:                            'lisp-listener-socket-daemon))
                    127:     (setf (getf (process-property-list lisp-listener-daemon) ':no-interrupts)
                    128:           t)))
                    129: 
                    130: (defvar *socket-pathname* nil)
                    131: 
                    132: (defun lisp-listener-socket-daemon ()
                    133:   (let (listen-socket-fd
                    134:        (listen-sockaddr
                    135:         (if *unix-domain*
                    136:             (make-cstruct 'sockaddr-un)
                    137:           (make-cstruct 'sockaddr-in)))
                    138:        (timeval (make-cstruct 'timeval))
                    139:        (mask-obj (make-cstruct 'unsigned-long))
                    140:        (int (make-cstruct 'unsigned-long))
                    141:        mask
                    142:        stream
                    143:        proc-name
                    144:        fd)
                    145:     
                    146:     (unless *socket-pathname*
                    147:       (format nil "~a/~a" (sys:getenv "HOME") ".excl_to_emacs"))
                    148: 
                    149:     (setf (timeval-sec timeval) 0
                    150:          (timeval-usec timeval) 0)
                    151:     (unwind-protect
                    152:        (progn
                    153:          (if *unix-domain* (errorset (delete-file *socket-pathname*)))
                    154:          (setq listen-socket-fd (socket
                    155:                                  (if *unix-domain* *af-unix* *af-inet*)
                    156:                                  *sock-stream*
                    157:                                  0))
                    158:          (when (< listen-socket-fd 0)
                    159:            (perror "socket")
                    160:            (setq listen-socket-fd nil)
                    161:            (return-from lisp-listener-socket-daemon nil))
                    162:          (mp::mpwatchfor listen-socket-fd)
                    163: 
                    164:          ;; Compute a select mask for the daemon's socket.
                    165:          (setq mask (ash 1 listen-socket-fd))
                    166: 
                    167:          (if* *unix-domain*
                    168:             then (setf (sockaddr-un-family listen-sockaddr) *af-unix*)
                    169:                  ;; Set pathname.
                    170:                  (dotimes (i (length *socket-pathname*)
                    171:                            (setf (sockaddr-un-path listen-sockaddr i) 0))
                    172:                    (setf (sockaddr-un-path listen-sockaddr i)
                    173:                      (char-int (elt *socket-pathname* i))))
                    174:             else ;; a crock:
                    175:                  (bzero listen-sockaddr (ff::cstruct-len 'sockaddr-in))
                    176:                  (setf (sockaddr-in-family listen-sockaddr) *af-inet*
                    177:                        (sockaddr-in-port listen-sockaddr) *inet-port*))
                    178:          
                    179:          (unless (zerop (bind listen-socket-fd
                    180:                               listen-sockaddr
                    181:                               (if *unix-domain*
                    182:                                   (+ (length *socket-pathname*) 2)
                    183:                                 (ff::cstruct-len 'sockaddr-in))))
                    184:            (perror "bind")
                    185:            (return-from lisp-listener-socket-daemon nil))
                    186: 
                    187:          (unless (zerop (unix-listen listen-socket-fd 5))
                    188:            (perror "listen")
                    189:            (return-from lisp-listener-socket-daemon nil))
                    190:          (loop
                    191:           (process-wait "waiting for a connection"
                    192:                         #'(lambda (mask mask-obj timeout)
                    193:                             (setf (unsigned-long-unsigned-long mask-obj) mask)
                    194:                             (not (zerop (select 32 mask-obj 0 0 timeout))))
                    195:                         mask mask-obj timeval)
                    196:           (setf (unsigned-long-unsigned-long int)
                    197:             (if *unix-domain*
                    198:                 (ff::cstruct-len 'sockaddr-un)
                    199:               (ff::cstruct-len 'sockaddr-in)))
                    200:           (setq fd (accept listen-socket-fd listen-sockaddr int))
                    201:           (when (< fd 0)
                    202:             (perror "accept")
                    203:             (return-from lisp-listener-socket-daemon nil))
                    204:           
                    205:           (setq stream
                    206:             (excl::make-buffered-terminal-stream fd fd t t))
                    207:           
                    208:           ;; the first thing that comes over the stream is the name of the
                    209:           ;; emacs buffer which was created--we name the process the same.
                    210:           (setq proc-name (read stream))
                    211:           
                    212:           (if* *unix-domain*
                    213:              then (process-run-function
                    214:                    proc-name
                    215:                    'lisp-listener-with-stream-as-terminal-io stream)
                    216:              else (let ((hostaddr (logand
                    217:                                    (sockaddr-in-addr listen-sockaddr) #xff)))
                    218:                     (format t ";;; starting listener-~d (host ~d)~%" fd
                    219:                             hostaddr)
                    220:                     (if* (and nil
                    221:                               ;; the next line checks that the connection
                    222:                               ;; is coming from the current machine
                    223:                               (not (eql 1 hostaddr))
                    224:                               )
                    225:                        then (format t ";;; access denied for addr ~s~%"
                    226:                                     hostaddr)
                    227:                             (refuse-connection fd)
                    228:                        else (process-run-function
                    229:                              proc-name
                    230:                              'lisp-listener-with-stream-as-terminal-io
                    231:                              stream))))))
                    232:       (when listen-socket-fd
                    233:        (mp::mpunwatchfor listen-socket-fd)
                    234:        (unix-close listen-socket-fd)
                    235:        (setq lisp-listener-daemon nil)))))
                    236: 
                    237: (defun refuse-connection (fd &aux s)
                    238:   (setq s (excl::make-buffered-terminal-stream fd fd t t))
                    239:   (setf (excl::sm_read-char s) #'mp::stm-bterm-read-string-char-wait)
                    240:   (format s "connection refused.~%")
                    241:   (force-output s)
                    242:   (setf (excl::sm_bterm-out-pos s) 0)
                    243:   (close s))
                    244: 
                    245: (defun lisp-listener-with-stream-as-terminal-io (s)
                    246:   (unwind-protect
                    247:       (progn
                    248:        (setf (excl::sm_read-char s) #'mp::stm-bterm-read-string-char-wait)
                    249:        (tpl:start-interactive-top-level
                    250:         s 'tpl:top-level-read-eval-print-loop nil))
                    251:     ;; This next crock is to prevent the force-output done by close from
                    252:     ;; signalling an error if there are characters buffered to the output
                    253:     ;; stream, which there will be if the remote client closed the connection.
                    254:     ;; This should be changed to a clear-output once that works on a buffered
                    255:     ;; terminal stream.
                    256:     (setf (excl::sm_bterm-out-pos s) 0)
                    257:     (close s)))
                    258: 
                    259: (defun open-network-stream (&key host port socket-file)
                    260:   "Open a stream to a port, which is a TCP/IP communication channel.  There
                    261: are two types of ports supported, UNIX and INTERNET domain.  The domain is
                    262: chosen based on the keyword arguments actually used: HOST and PORT are for
                    263: internet domain ports and SOCKET-FILE is for unix domain ports."
                    264:   (if (and (or (null host) (null port))
                    265:           (null socket-file))
                    266:       (error "Must either supply HOST and PORT *or* SOCKET-FILE keywords."))
                    267:   (if* socket-file
                    268:      then ;; UNIX domain
                    269:          (let ((server (make-cstruct 'sockaddr-un))
                    270:                socket-fd)
                    271:            (setf (sockaddr-un-family server) *af-unix*)
                    272:            (dotimes (i (length socket-file)
                    273:                      (setf (sockaddr-un-path server i) 0))
                    274:              (setf (sockaddr-un-path server i)
                    275:                (char-int (elt socket-file i))))
                    276:            (setq socket-fd (socket *af-unix* *sock-stream* 0))
                    277:            (if (< (connect socket-fd server (+ 2 (length socket-file))) 0)
                    278:                (error "connect failed to ~s" socket-file))
                    279:            (excl::make-buffered-terminal-stream socket-fd socket-fd t t))
                    280:      else ;; INTERNET domain
                    281:          (let (sock server hostaddress)
                    282:            ;; Open a socket
                    283:            (when (< (setf sock (socket *af-inet* *sock-stream* 0)) 0)
                    284:              (error "couldn't open socket"))
                    285:            ;; construct a socket address
                    286:            (setf server (make-cstruct 'sockaddr-in))
                    287:            (bzero server (ff::cstruct-len 'sockaddr-in))
                    288:            (when (= (setf hostaddress (gethostbyname host)) 0)
                    289:              (error "unknown host: ~a" host))
                    290:            ;; This next line is what they invented the word "hack" for.
                    291:            ;; If I knew how to pass the address of the addr field in server, I
                    292:            ;; wouldn't have to do this.
                    293:            ;; Be sure that this precedes writes to other fields in server.
                    294:            (if (not (= 4 (hostent-length hostaddress)))
                    295:                (error "address length not 4"))
                    296:            (setf (sockaddr-in-addr server)
                    297:              (si:memref-int (hostent-addr hostaddress) 0 0 :unsigned-long))
                    298:            (setf (sockaddr-in-family server) *af-inet*)
                    299:            (setf (sockaddr-in-port server) port)
                    300:            ;; open the connection
                    301:            (when (< (connect sock server (ff::cstruct-len 'sockaddr-in)) 0)
                    302:              (unix-close sock)
                    303:              (error "couldn't connect to socket"))
                    304:            ;; build and return the stream
                    305:            (excl::make-buffered-terminal-stream sock sock t t))))

unix.superglobalmegacorp.com

This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.