[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

Sun/Symbolics Ethernet I/F



Here's something I hacked down in order to learn how to connect our Vax
(Ultrix) via TCP/IP to a Lisp-Machine. It's the VAX -> LISPM side only,
but using the stuff Doug Evans sent it shouldn't be that complicated to
get it working in the other direction too. It would be nice if you'd let
me know about improvements.

I'll CC this to SLUG, because the Unix side might be interesting to more
than one person. Don't know what "duckpin" means (I'm a poor uninitiated
german :-) but I hope the code helps anyway.


	--jc

The first file is the lispm (user) side of the connection, while the
second file contains the C code running on our Vax.

;1;; -*- Mode: LISP; Syntax: Common-lisp; Package: USER; Base: 10 -*-
;;;========================================================================
;;;
;;; Client side for access of user defined tcp/ip servers on a unix host.
;;;
;;;
;;; Author: JC@sysiphos.gmd.de
;;; Date:   01/16/89
;;;
;;; History:
;;;   01/16/89: (JC) added *fortune-server* defvar
;;;   10/20/88: (JC) created
;;; End.


;;; <detailed description> follows

0(defvar 2*fortune-server*1 "z" "The host which advertised cookies on the net")

;;; A server host for protocol :cookie needs a namespace entry of
;;; <Service: FORTUNE TCP COOKIE> in order to make this user side work

;; user side of network protocol...  (the stuff the lispm needs to know to connect to
;; a FORTUNE-Server)
0(neti:define-protocol 2:cookie0 (:fortune :byte-stream)
  (:desirability .8)
  (:invoke-with-stream-and-close ((stream :ascii-translation t))
    (loop as ch = (read-char stream nil :eof)
	  do
      (cond ((eq ch :eof)
	     (return))
	    ((char= ch #\line)
	     (write-char #\return))
	    (t (write-char ch))))))

1;;; ... and make it known 
0(tcp:add-tcp-port-for-protocol :cookie 8192)

1;;; test
0(define-cp-command (2give-cookie0 :command-table "global") ()
    (neti:invoke-service-on-host :fortune (neti:parse-host *fortune-server*)))

1;;; server side ... (the stuff needed to allow other machines asking us for a cookie)
;;; 0(neti:define-server 1<to be defined>)

;;;========================================================================EOF.

0and now for the Unix C file

/* Mode: C; */
/*
 * fortuned
 *
 *  Fortune daemon running on a Vax and serving requests for a cookie
 *  coming in via TCP/IP. Requests are served on a single server base.
 *  This will need forking of subprocesses if servicing will take a
 *  noticable amount of time.
 *
 * Acknowledgements: For opening TCP/IP streams I adapted example code 
 * shown in a SUN technical bulletin (June 88?)
 *
 */

#include <stdio.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <netdb.h>		/* network database routines header file */

#include "fatal.c"		/* simple error handler */

#define MY_PORT 8192		/* check this against /etc/services */
#define DOUT 1			/* data out file desc, here stdout */

main(argc, argv)
     int argc;
     char *argv[];
{
  switch ( argc ) {
  case 1:
    server();
    break;
  case 2: 
    client(argv[1]);
  default:
    fprintf(stderr, "Usage: %s [ remote host ]\n", argv[0]);
    exit(1);
  }
  exit(0);
}

client(server_name)
     char *server_name;
{
  fprintf(stderr, "no client mode available, sorry");
}


server()
{
  struct sockaddr_in saddr, caddr;
  int sd;
  int nsd;
  int caddr_len = sizeof(caddr);

  /* the servers file handle */

  if((sd = socket(AF_INET, SOCK_STREAM, 0)) < 0) {
    perror("server: socket");
    exit(1);
  }

  /* The server binds to any address and therefore can accept		*/
  /* connections from any host as long as they make the request on the	*/
  /* proper port.	*/

  bzero((char *)&saddr, sizeof(saddr));
  saddr.sin_family = AF_INET;
  saddr.sin_addr.s_addr = htonl(INADDR_ANY);
  saddr.sin_port = htons(MY_PORT);

  if(bind(sd, &saddr, sizeof(saddr)) < 0) {
    perror("server: bind");
    exit(1);
  }

  /* Listen tells the lower network layers how many outstanding pending	*/
  /* connections we are willing to have backlogged. In this case 1.	*/

  if(listen(sd, 1) < 0) {
    perror("server: listen");
    exit(1);
  }

  /* We can continue to accept connections on this port indefinitely.	*/
  /* The server process could be forked, but in this example we just	*/
  /* process the connections one at a time.				*/

  while((nsd = accept(sd, &caddr, &caddr_len)) >= 0) {
    top_level(nsd);
    close(nsd);
  }

  /* We only get here if the accept returns an error */

  perror("server: accept");
  close(sd);
  exit(1);
}


top_level(sd)
     int sd;
{
  switch(fork()) {
  case -1:			/* error */
    fatal("server: fork");
  case 0:			/* child */
    top_level1(sd);
    break;
  default:			/* parent */
    return;
  }
}


  /* The remainder of this function is executed by the child only */

int top_level1(sd)
     int sd;
{
  /* We want to call a unix command and redirect its standard output	*/
  /* to the network stream. The dup(filedesc) call returns a new file	*/
  /* descriptor that refers to the same open file as the filedesc file	*/
  /* descriptor. The new file descriptor is the lowest number available.*/
  /* Since stdin, stdout and stderr have values of 0,1 and 2 resp. this	*/
  /* will redirect stdout: 	*/

  close(1);
  if(dup(sd) < 0)
    fatal("server: dup");
  
  /* Now the ipc socket is used as stdout */

  execl("/usr/games/fortune", "-a", (char **)0);

}