#|| -*- Mode:LISP; Package:(TUBE GLOBAL); Base:10; Fonts:(CPTFONTB) -*- TUBES ARE BIDRECTIONAL COMMUNICATIONS STREAMS. YOU CAN TALK IN ONE END AND LISTEN ON THE OTHER. AKA TIN-CAN TELEPHONE. simple utility functions for interprocess communication streams 6/28/85 17:09:39 -george carrette TUBES There are two functions for setting up tubes: (TUBE:GET-REMOTE-TUBE "") Will return all tubes of "" that have been opened up to this machine. (TUBE:OPEN-TUBE "" "") Will open up a tube named "" to the host "". (TUBE:REMOTE-TUBE-NAMES) returns a list of names for which TUBE:GET-REMOTE-TUBE will return a non-null value. Tubes may or may not need unique names depending on the setting of the variable TUBE:*REMOTE-TUBE-UNIQUE-CHECK-P*, which defaults to T. If this is T then it is an error to open more than one tube of a given name to a given host. When outputing to a TUBE, use :TYO or any of the usual IO functions such as PRINT. A :FORCE-OUTPUT may need to be done on a TUBE to make sure that the output gets to the other side (machine). When inputting from a TUBE, use :TYI or any of the usual IO functions such as READ. A demonstration/test program, TUBE-TALK. On machine "LAM-A" do: (TUBE:TUBE-TALK "test" "LAM-B") On machine "LAM-B" do: (TUBE:TUBE-TALK "test") This simple demo is like a telephone in that it is confusing to both talk at the same time. Debugging functions: (TUBE:PRINT-TUBES) prints out information about tubes. (TUBE:RESET-TUBES) closes in abort mode all tubes and removes them from the list of tubes. ||# (DEFVAR *REMOTE-TUBES* NIL) (ADD-INITIALIZATION "TUBE" '(PROCESS-RUN-FUNCTION "TUBE SERVER" 'SETUP-REMOTE-TUBE) NIL 'CHAOS:SERVER-ALIST) (defvar *remote-TUBE-unique-check-p* t) (DEFUN SETUP-REMOTE-TUBE (&AUX STREAM CONN PKT ST N) (SETQ STREAM (CHAOS:OPEN-STREAM NIL "TUBE")) (SETQ CONN (SEND STREAM :CONNECTION)) (SETQ PKT (CHAOS:CONN-READ-PKTS CONN)) (COND ((NULL PKT) (CHAOS:REJECT CONN "INTERNAL ERROR")) ((NOT (SETQ N (STRING-SEARCH-CHAR #\SPACE (SETQ ST (CHAOS:PKT-STRING PKT))))) (CHAOS:REJECT CONN "NO TUBE NAME GIVEN")) ((and (GET-REMOTE-TUBE (SETQ ST (string-trim " " (SUBSTRING ST N)))) *remote-TUBE-unique-check-p*) (CHAOS:REJECT CONN "Already have a TUBE by that name here")) ('ELSE (PUSH (LIST ST STREAM) *REMOTE-TUBES*) (CHAOS:ACCEPT CONN)))) (DEFUN GET-REMOTE-TUBE (NAME) (if *remote-TUBE-unique-check-p* (CADR (ASS #'STRING-EQUAL NAME *REMOTE-TUBES*)) (VALUES-LIST (MAPCAR #'CADR (SUBSET #'(LAMBDA (X) (STRING-EQUAL (CAR X) NAME)) *REMOTE-TUBES*))))) (DEFUN REMOTE-TUBE-NAMES () "Returns the names of all open remote tubes" (DO ((NAMES NIL (IF (NOT (MEM #'(LAMBDA (TN E) (STRING-EQUAL TN (CADR E))) (CAAR L) (CDR L))) (CONS (CAAR L) NAMES) NAMES)) (L *REMOTE-TUBES* (CDR L))) ((NULL L) NAMES))) (DEFVAR *LOCAL-TUBES* NIL) (DEFUN OPEN-TUBE (HOST NAME) (CHECK-TYPE NAME STRING) (LET ((S (IF (EQ SI:LOCAL-HOST (SI:PARSE-HOST HOST)) (OPEN-TUBE-TO-SELF NAME) (CHAOS:OPEN-STREAM HOST (STRING-APPEND "TUBE " NAME))))) (PUSH (LIST HOST NAME S) *LOCAL-TUBES*) S)) (DEFUN GET-LOCAL-TUBE (HOST NAME) (CADDR (CAR (MEM #'(LAMBDA (PS X) (AND (EQ (SI:PARSE-HOST (CAR X)) PS) (STRING-EQUAL NAME (CADR X)))) (SI:PARSE-HOST HOST) *LOCAL-TUBES*)))) (DEFFLAVOR LOCAL-TUBE (INPUT-IO-BUFFER (UNTYI-CHAR NIL) OUTPUT-IO-BUFFER (OPEN T)) () :INITABLE-INSTANCE-VARIABLES) (DEFUN MAKE-LOCAL-TUBE () (LET ((I (TV:MAKE-IO-BUFFER 100)) (O (TV:MAKE-IO-BUFFER 100))) (VALUES (MAKE-INSTANCE 'LOCAL-TUBE :INPUT-IO-BUFFER I :OUTPUT-IO-BUFFER O) (MAKE-INSTANCE 'LOCAL-TUBE :INPUT-IO-BUFFER O :OUTPUT-IO-BUFFER I)))) (DEFUN TUBE-NOT-OPEN () (FERROR NIL "tube is closed for I//O operations")) (DEFMETHOD (LOCAL-TUBE :TYI) (&OPTIONAL IGNORE) (OR OPEN (TUBE-NOT-OPEN)) (COND (UNTYI-CHAR (PROG1 UNTYI-CHAR (SETQ UNTYI-CHAR NIL))) ('ELSE (TV:IO-BUFFER-GET INPUT-IO-BUFFER)))) (DEFMETHOD (LOCAL-TUBE :TYI-NO-HANG) () (OR OPEN (TUBE-NOT-OPEN)) (COND (UNTYI-CHAR (PROG1 UNTYI-CHAR (SETQ UNTYI-CHAR NIL))) ('ELSE (TV:IO-BUFFER-GET INPUT-IO-BUFFER T)))) (DEFMETHOD (LOCAL-TUBE :LISTEN) () (OR OPEN (TUBE-NOT-OPEN)) (LET ((C (SEND SELF :TYI-NO-HANG))) (COND ((NULL C) NIL) ('ELSE (SEND SELF :UNTYI C) T)))) (DEFMETHOD (LOCAL-TUBE :UNTYI) (C) (OR OPEN (TUBE-NOT-OPEN)) (SETQ UNTYI-CHAR C)) (DEFMETHOD (LOCAL-TUBE :TYO) (C) (OR OPEN (TUBE-NOT-OPEN)) (TV:IO-BUFFER-PUT OUTPUT-IO-BUFFER C)) (DEFMETHOD (LOCAL-TUBE :STRING-OUT) (&OPTIONAL ARG1 &REST ARGS) (OR OPEN (TUBE-NOT-OPEN)) (STREAM-DEFAULT-HANDLER SELF :STRING-OUT ARG1 ARGS)) (DEFMETHOD (LOCAL-TUBE :CLOSE) (&OPTIONAL IGNORE) (SETQ OPEN NIL)) (DEFMETHOD (LOCAL-TUBE :FORCE-OUTPUT) () T) (DEFUN OPEN-TUBE-TO-SELF (NAME) (IF (AND *remote-TUBE-unique-check-p* (GET-REMOTE-TUBE NAME)) (FERROR NIL "Already have a TUBE by that name")) (MULTIPLE-VALUE-BIND (A B) (MAKE-LOCAL-TUBE) (PUSH (LIST NAME B) *REMOTE-TUBES*) A)) (COMPILE-FLAVOR-METHODS LOCAL-TUBE) (DEFUN PRINT-TUBES () (FORMAT T "~&Tubes connected to us:~%") (dolist (tube *REMOTE-TUBES*) (format t "Tube named: ~S, Stream: ~S~%" (car tube) (cadr tube))) (FORMAT T "~&Tube connections we have initiated:~%") (dolist (tube *LOCAL-TUBES*) (format t "To host: ~S, tube named: ~S, Stream: ~S~%" (car tube) (cadr tube) (caddr tube))) NIL) (DEFUN RESET-TUBES () (FORMAT T "~&Tubes connected to us:~%") (dolist (tube *REMOTE-TUBES*) (format t "Tube named: ~S, Stream: ~S~%" (car tube) (cadr tube)) (CLOSE (CADR TUBE) T) (SETQ *REMOTE-TUBES* (DELQ TUBE *REMOTE-TUBES*))) (FORMAT T "~&Tube connections we have initiated:~%") (dolist (tube *LOCAL-TUBES*) (format t "To host: ~S, tube named: ~S, Stream: ~S~%" (car tube) (cadr tube) (caddr tube)) (CLOSE (CADDR TUBE) T) (SETQ *LOCAL-TUBES* (DELQ TUBE *LOCAL-TUBES*))) NIL) (DEFUN TUBE-TALK (TUBE-NAME &OPTIONAL HOST) (COND ((NULL HOST) (TALK-ON-TUBE (OR (GET-REMOTE-TUBE TUBE-NAME) (RETURN-FROM TUBE-TALK "NOBODY CONNECTED TO THAT TUBE")))) ('ELSE (TALK-ON-TUBE (OR (GET-LOCAL-TUBE HOST TUBE-NAME) (OPEN-TUBE HOST TUBE-NAME)))))) (DEFUN TALK-ON-TUBE (X) (DO ((C)) (NIL) (PROCESS-WAIT "keyboard or Tube" #'(LAMBDA (A B) (OR (SEND A :LISTEN) (send b :listen))) X TERMINAL-IO) (WHEN (SETQ C (SEND TERMINAL-IO :TYI-NO-HANG)) (COND ((NOT (ZEROP (CHAR-BITS C))) (FORMAT TERMINAL-IO "")) ('ELSE (SEND TERMINAL-IO :TYO C) (SEND X :TYO C) (SEND X :FORCE-OUTPUT)))) (WHEN (SETQ C (SEND X :TYI-NO-HANG)) (SEND TERMINAL-IO :TYO C)))) (DEFUN UNIX-TUBE-TALK (&OPTIONAL (TUBE-NAME "UNX")) (DO ((LINE) (X (or (get-remote-tube TUBE-NAME) (return-from unix-tube-talk "no unix connected")))) (nil) (setq line (read-delimited-string (tiger:ascii-code #\line) x)) (send terminal-io :line-out line) (setq line (prompt-and-read :string "~&To Unix>")) (send x :string-out line) (send x :tyo (tiger:ascii-code #\line)) (send x :force-output)))