From: Jeffrey Putnam
Subject: KCL and sockets
Date: 
Message-ID: <186@imagine.PAWL.RPI.EDU>
I am looking for a KCL socket library.  At a minimum, i would like to 
be able to make connections to internet ports and set options on the
sockets.  I would like this to be accessible from lisp - like the
file manipulation stuff, but it clearly needs to be written in C.  
(Actually im looking for NeWS interface code in lisp, but given the
socket stuff, the rest is fairly straightforward.)

Does anyone have such code?   I dont think it would be that tough to
do (having looked at doing it in the past - but never having the
spare time to put into it).  

Please respond by posting (i know, i should read the netiquette postings, 
i have read them).  I cannot receive mail on any local machine for a while.

thanks... 
jeff putnam
From: Bruce K. Holmer
Subject: Re: KCL and sockets
Date: 
Message-ID: <22429@ucbvax.BERKELEY.EDU>
In article <ยทยทยท@imagine.PAWL.RPI.EDU> You cant get here from there. writes:
>I am looking for a KCL socket library.  At a minimum, i would like to 
>be able to make connections to internet ports and set options on the
>sockets.  I would like this to be accessible from lisp - like the
>file manipulation stuff, but it clearly needs to be written in C.  

Here is something that partially fulfils your request.
You can easily add more arguments so that socket options can be specified.
It works only for BSD based systems (BSD 4.x and SUN unix).
I used this in a program that directly interacts with a news server
using NNTP (in my case, ucbvax).

;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
; The following is from a file named `connect.lsp'.
; Defines the function `connect' which takes two arguments: hostname (string)
;    and port (integer).
; The function makes the connection and returns a two-way stream.

(set-macro-character
  #\%
  #'(lambda (stream char)
	    (declare (ignore char))
	    (values (read-line stream))))

(Clines

%
%#define MAXHOSTNAME 80
%
%#include <sys/types.h>
%#include <sys/socket.h>
%#include <netinet/in.h>
%#include <netdb.h>
%#include <stdio.h>
%
%	extern object Sstring_char;
%
%	object connect_x(hostname, port)
%	object hostname;
%	int port;
%	{
%		object socket_io, socket_in, socket_out;
%		char host[MAXHOSTNAME];
%		int sock, i;
%		FILE *fp_in, *fp_out;
%		struct sockaddr_in server;
%		struct hostent *hp, *gethostbyname();
%
%		if (hostname->st.st_fillp > MAXHOSTNAME - 1)
%			FEerror("host name too long", 0);
%		for (i = 0; i < hostname->st.st_fillp; i++)
%			host[i] = hostname->st.st_self[i];
%		host[i] = '\0';
%
%		/* create socket */
%
%		sock = socket(AF_INET, SOCK_STREAM, 0);
%		if (sock == -1)
%			FEerror("could not open socket", 0);
%		fp_in = fdopen(sock, "r");
%		fp_out = fdopen(sock, "w");
%		setbuf(fp_in, NULL);
%		setbuf(fp_out, NULL);
%
%		/* connect socket using hostname and portnumber */
%
%		server.sin_family = AF_INET;
%		hp = gethostbyname(host);
%		if (hp == NULL)
%			FEerror("~S:  unknown host", 1, hostname);
%		bcopy(hp->h_addr, &server.sin_addr, hp->h_length);
%		server.sin_port = htons(port);
%		if (connect(sock, &server, sizeof(server)) == -1)
%			FEerror("connecting stream socket", 0);
%
%		socket_in = alloc_object(t_stream);
%		socket_in->sm.sm_mode = (short)smm_input;
%		socket_in->sm.sm_fp = fp_in;
%		socket_in->sm.sm_object0 = Sstring_char;
%		socket_in->sm.sm_object1 = hostname;
%		socket_in->sm.sm_int0 = socket_in->sm.sm_int1 = 0;
%
%		socket_out = alloc_object(t_stream);
%		socket_out->sm.sm_mode = (short)smm_output;
%		socket_out->sm.sm_fp = fp_out;
%		socket_out->sm.sm_object0 = Sstring_char;
%		socket_out->sm.sm_object1 = hostname;
%		socket_out->sm.sm_int0 = socket_out->sm.sm_int1 = 0;
%
%		socket_io = make_two_way_stream(socket_in, socket_out);
%
%		return (socket_io);
%	}

)

(defentry connect (object int) (object connect_x))
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;

The hard part is to get this code to work with KCL.
First KCL's cmpinclude.h file must be modified.  Just copy it to your
working directory and add the following (given here as ed commands):

--------------------------------------------------------------------------------
209a
	struct stream   sm;	/* goes in `union lispunion' */
.
163a
enum smmode {			/*  stream mode  */
	smm_input,		/*  input  */
	smm_output,		/*  output  */
	smm_io,			/*  input-output  */
	smm_probe,		/*  probe  */
	smm_synonym,		/*  synonym  */
	smm_broadcast,		/*  broadcast  */
	smm_concatenated,	/*  concatenated  */
	smm_two_way,		/*  two way  */
	smm_echo,		/*  echo  */
	smm_string_input,	/*  string input  */
	smm_string_output	/*  string output  */
};

struct stream {
	short	t, m;
	FILE	*sm_fp;		/*  file pointer  */
	object	sm_object0;	/*  some object  */
	object	sm_object1;	/*  some object */
	int	sm_int0;	/*  some int  */
	int	sm_int1;	/*  some int  */
	short	sm_mode;	/*  stream mode  */
				/*  of enum smmode  */
};
.
--------------------------------------------------------------------------------

In KCL the following will compile and load the function:

	(compile-file "connect.lsp")
	(si:faslink "connect" "-lc")

An example of the function's use is:

	(setf x (connect "ucbvax" 119))		; connect to news server
	(read-line x)				; read the start up message
	...
	(write-line "quit" x)			; send the command to quit
	...
	(read-line x)				; read the sign-off message
	...
	(close x)				; close the stream

Note that the responses from the news server have a return in them that should
be removed as in:
	(remove #\Return (read-line news-server-stream))