From: Charlie
Subject: Can I connect to a local socket?
Date: 
Message-ID: <bk4p1u$phlq9$1@ID-155962.news.uni-berlin.de>
Hi,
	I've got a local socket server in C and I'm trying to get my clisp to
connect to it but as it's a local socket it doesn't seem to have a port
number so I can't use (socket:socket-connect).
	I have also tried to open the socket file as a file with:

(with-open-file (sock (merge-pathnames (user-home-pathname) "test"))
	:direction :output
	:element-type 'character)
	(loop for i from - to 100
		do (write-char #\A)))

but I get "UNIX error 6 (ENXIO): no such device or address" presumably
because the socket is not a "proper" file.
The socket file is called test and in the expected place.

Can anyone tell me the correct approach?

The C code for the server is from
http://www.advancedlinuxprogramming.com/listings/chapter-5/socket-server.c
and all it does it listen, echo and quit on command.

Thanks
Charlie

From: Joe Marshall
Subject: Re: Can I connect to a local socket?
Date: 
Message-ID: <brtmc8la.fsf@ccs.neu.edu>
Charlie <·····@nowhere.co.uk> writes:

> Hi,
> 	I've got a local socket server in C and I'm trying to get my clisp to
> connect to it but as it's a local socket it doesn't seem to have a port
> number so I can't use (socket:socket-connect).
> 	I have also tried to open the socket file as a file with:
>
> (with-open-file (sock (merge-pathnames (user-home-pathname) "test"))
> 	:direction :output
> 	:element-type 'character)
> 	(loop for i from - to 100
> 		do (write-char #\A)))
>
> but I get "UNIX error 6 (ENXIO): no such device or address" presumably
> because the socket is not a "proper" file.
> The socket file is called test and in the expected place.
>
> Can anyone tell me the correct approach?

with-open-file simply won't do it.  You'll have to use socket-connect,
but you'll also have to synthesize a local sockaddr for it.
I don't know the implementation you are using, so it may be the case
that you can't get socket-connect to take a local sockaddr.  If that's
the case, then you'll have to go through the foreign function interface.
From: Charlie Burrows
Subject: Re: Can I connect to a local socket?
Date: 
Message-ID: <bk6j0b$q6n3e$1@ID-155962.news.uni-berlin.de>
Thank-you. I'm using CLISP, it's (socket:socket-connect port) must have
a port number. I can't see anything about local sockets in the CLISP
documentation but maybe I have just missed it. I guess I'm going to have
to use internet ports as I'm set on using clisp and I don't want to get
into FFI at this stage.

Joe Marshall wrote:
> Charlie <·····@nowhere.co.uk> writes:
> 
> 
>>Hi,
>>	I've got a local socket server in C and I'm trying to get my clisp to
>>connect to it but as it's a local socket it doesn't seem to have a port
>>number so I can't use (socket:socket-connect).
>>	I have also tried to open the socket file as a file with:
>>
>>(with-open-file (sock (merge-pathnames (user-home-pathname) "test"))
>>	:direction :output
>>	:element-type 'character)
>>	(loop for i from - to 100
>>		do (write-char #\A)))
>>
>>but I get "UNIX error 6 (ENXIO): no such device or address" presumably
>>because the socket is not a "proper" file.
>>The socket file is called test and in the expected place.
>>
>>Can anyone tell me the correct approach?
> 
> 
> with-open-file simply won't do it.  You'll have to use socket-connect,
> but you'll also have to synthesize a local sockaddr for it.
> I don't know the implementation you are using, so it may be the case
> that you can't get socket-connect to take a local sockaddr.  If that's
> the case, then you'll have to go through the foreign function interface.
> 
From: Rob Warnock
Subject: Re: Can I connect to a local socket?
Date: 
Message-ID: <c2ydnXpA2bpBYvuiXTWc-w@speakeasy.net>
Charlie Burrows  <···············@riskdecisions.com> wrote:
+---------------
| Thank-you. I'm using CLISP, it's (socket:socket-connect port) must have
| a port number. I can't see anything about local sockets in the CLISP
| documentation but maybe I have just missed it. I guess I'm going to have
| to use internet ports as I'm set on using clisp and I don't want to get
| into FFI at this stage.
+---------------

Well, before giving up on local sockets completely you may want to
take a look at the CLX code for CLISP, or should I say, the code in
"${CLISP-2.29}/src/socket.d" (which turns into a ".c" during the build).
It contains code to do an AF_UNIX connect, but *only* to the X server
[look at what routine "connect_to_x_server(host,display)" does when
fed a host of "unix"].

Unfortunately, they didn't expose this to ordinary mortals; that
particular routine has the paths for X local sockets hard-coded
into it. But you should be able to clone the code easily enough
and pass an arbitrary local socket path to the clone.

Hmmm... Or, if are lucky enough to be able to pick the local socket path
yourself, then just use the "connect_to_x_server()" routine as is, and
call it with a very high number (much higher than the number of X displays
on on your system -- but be careful, SSH starts with #10 and up for its
tunneled X connections!). For example, if you call:

	connect_to_x_server("unix", 100)

it would try to connect to "/tmp/.X11-unix/X100". You can in fact do this
[I just tried it!] by calling:

	(system::make-socket-stream "unix" 100)

Caveat: You get back an #<IO UNBUFFERED X11-SOCKET-STREAM ("unix" 100)>,
which cannot be written on by WRITE-CHAR or WRITE-LINE or WRITE-SEQUENCE --
you have to use WRITE-BYTE. But using a loop wrapped around this this:

	(defun test-write-line (line s)
	  (loop for i across line do
	    (write-byte (char-code i) s))
	    (write-byte 13 s)
	    (write-byte 10 s)
	    (force-output s)
	    line)

I was able to push an HTTP request to a "mod_lisp"-like server.

CAVEAT#2: I couldn't figure out any way to call "shutdown(sock, SHUT_WR)"
on the stream, so protocols that depend on the other end seeing an EOF
from you before they reply [such as the above-mentioned "mod_lisp"-like
server!] may be a bit hard to use...   :-(

Good luck!


-Rob

-----
Rob Warnock, PP-ASEL-IA		<····@rpw3.org>
627 26th Avenue			<URL:http://rpw3.org/>
San Mateo, CA 94403		(650)572-2607
From: Charlie
Subject: Re: Can I connect to a local socket?
Date: 
Message-ID: <bk722m$por51$1@ID-155962.news.uni-berlin.de>
Wow, this seems quite far above my head. My main concerns were security, 
speed (untested assumption based on complexity), the fact that it's 
never going to be used over a network and above all (at this stage) 
simplicity.
I'm using lisp to generate data and pass it to a C process for display. 
I'm just getting it written quickly right now so too much complexity 
will kill momentum and that's no good. I guess I'll just use IP sockets 
and maybe change later.

Rob Warnock wrote:

> Charlie Burrows  <···············@riskdecisions.com> wrote:
> +---------------
> | Thank-you. I'm using CLISP, it's (socket:socket-connect port) must have
> | a port number. I can't see anything about local sockets in the CLISP
> | documentation but maybe I have just missed it. I guess I'm going to have
> | to use internet ports as I'm set on using clisp and I don't want to get
> | into FFI at this stage.
> +---------------
> 
> Well, before giving up on local sockets completely you may want to
> take a look at the CLX code for CLISP, or should I say, the code in
> "${CLISP-2.29}/src/socket.d" (which turns into a ".c" during the build).
> It contains code to do an AF_UNIX connect, but *only* to the X server
> [look at what routine "connect_to_x_server(host,display)" does when
> fed a host of "unix"].
> 
> Unfortunately, they didn't expose this to ordinary mortals; that
> particular routine has the paths for X local sockets hard-coded
> into it. But you should be able to clone the code easily enough
> and pass an arbitrary local socket path to the clone.
> 
> Hmmm... Or, if are lucky enough to be able to pick the local socket path
> yourself, then just use the "connect_to_x_server()" routine as is, and
> call it with a very high number (much higher than the number of X displays
> on on your system -- but be careful, SSH starts with #10 and up for its
> tunneled X connections!). For example, if you call:
> 
> 	connect_to_x_server("unix", 100)
> 
> it would try to connect to "/tmp/.X11-unix/X100". You can in fact do this
> [I just tried it!] by calling:
> 
> 	(system::make-socket-stream "unix" 100)
> 
> Caveat: You get back an #<IO UNBUFFERED X11-SOCKET-STREAM ("unix" 100)>,
> which cannot be written on by WRITE-CHAR or WRITE-LINE or WRITE-SEQUENCE --
> you have to use WRITE-BYTE. But using a loop wrapped around this this:
> 
> 	(defun test-write-line (line s)
> 	  (loop for i across line do
> 	    (write-byte (char-code i) s))
> 	    (write-byte 13 s)
> 	    (write-byte 10 s)
> 	    (force-output s)
> 	    line)
> 
> I was able to push an HTTP request to a "mod_lisp"-like server.
> 
> CAVEAT#2: I couldn't figure out any way to call "shutdown(sock, SHUT_WR)"
> on the stream, so protocols that depend on the other end seeing an EOF
> from you before they reply [such as the above-mentioned "mod_lisp"-like
> server!] may be a bit hard to use...   :-(
> 
> Good luck!
> 
> 
> -Rob
> 
> -----
> Rob Warnock, PP-ASEL-IA		<····@rpw3.org>
> 627 26th Avenue			<URL:http://rpw3.org/>
> San Mateo, CA 94403		(650)572-2607
> 
From: Greg Menke
Subject: Re: Can I connect to a local socket?
Date: 
Message-ID: <m3vfrt9brt.fsf@europa.pienet>
Charlie Burrows <···············@riskdecisions.com> writes:

> Thank-you. I'm using CLISP, it's (socket:socket-connect port) must have
> a port number. I can't see anything about local sockets in the CLISP
> documentation but maybe I have just missed it. I guess I'm going to have
> to use internet ports as I'm set on using clisp and I don't want to get
> into FFI at this stage.

Do you mean you don't want an IP socket, but Unix Domain socket?  Is
there any particular reason why an IP socket is inappropriate?

Gregm
From: Rob Warnock
Subject: Re: Can I connect to a local socket?
Date: 
Message-ID: <c2ydnXVA2bqInPqiXTWc-w@speakeasy.net>
Greg Menke  <··········@toadmail.com> wrote:
+---------------
| Charlie Burrows <···············@riskdecisions.com> writes:
| 
| > Thank-you. I'm using CLISP, it's (socket:socket-connect port) must have
| > a port number. I can't see anything about local sockets in the CLISP
| > documentation but maybe I have just missed it. I guess I'm going to have
| > to use internet ports as I'm set on using clisp and I don't want to get
| > into FFI at this stage.
| 
| Do you mean you don't want an IP socket, but Unix Domain socket?
| Is there any particular reason why an IP socket is inappropriate?
+---------------

Security, perhaps?

Myself, I am very careful to use *only* Unix domain sockets for both
the connection between Apache and my Lisp server, and between the Lisp
server and PostgreSQL -- no IP/TCP listeners for the port scanners to
slip a wedge into. [Yes, that system sits right on the Internet...]


-Rob

-----
Rob Warnock, PP-ASEL-IA		<····@rpw3.org>
627 26th Avenue			<URL:http://rpw3.org/>
San Mateo, CA 94403		(650)572-2607
From: Boris Kolpackov
Subject: Re: Can I connect to a local socket?
Date: 
Message-ID: <bk7cjk$q7rje$1@ID-204145.news.uni-berlin.de>
····@rpw3.org (Rob Warnock) writes:

> Security, perhaps?
> 
> Myself, I am very careful to use *only* Unix domain sockets for both
> the connection between Apache and my Lisp server, and between the Lisp
> server and PostgreSQL -- no IP/TCP listeners for the port scanners to
> slip a wedge into. [Yes, that system sits right on the Internet...]

You can bind your socket to localhost (127.0.0.1) with the same effect.

hth,
-boris

-- 
Boris Kolpackov  http://kolpackov.net
3072R/AE084F1D - F608 942F 312E D82E 5B84  0407 C880 290B AE08 4F1D
From: Björn Lindberg
Subject: Re: Can I connect to a local socket?
Date: 
Message-ID: <hcssmmtx2pw.fsf@knatte.nada.kth.se>
Charlie <·····@nowhere.co.uk> writes:

> Hi,
> 	I've got a local socket server in C and I'm trying to get my clisp to
> connect to it but as it's a local socket it doesn't seem to have a port
> number so I can't use (socket:socket-connect).
> 	I have also tried to open the socket file as a file with:
> 
> (with-open-file (sock (merge-pathnames (user-home-pathname) "test"))
> 	:direction :output
> 	:element-type 'character)
> 	(loop for i from - to 100
> 		do (write-char #\A)))
> 
> but I get "UNIX error 6 (ENXIO): no such device or address" presumably
> because the socket is not a "proper" file.
> The socket file is called test and in the expected place.
> 
> Can anyone tell me the correct approach?
> 
> The C code for the server is from
> http://www.advancedlinuxprogramming.com/listings/chapter-5/socket-server.c
> and all it does it listen, echo and quit on command.

I got interested, and tried to write the client program in CMUCL, but
I cannot get it to work either. This is my code:

(defun send-message (message)
  (let* ((socket (ext:connect-to-unix-socket "/tmp/socket"))
         (stream (sys:make-fd-stream socket
                                     :input t
                                     :output t
                                     :buffering :none)))
    (format stream message)))

(send-message "hello there!")

I get the following error in the window where I started the server:

4206 ·····@nex:~/src/socket> server /tmp/socket
(null)
Memory fault

The C client program works well. Does anyone know what is wrong?


Bjorn
From: Eric Marsden
Subject: Re: Can I connect to a local socket?
Date: 
Message-ID: <wzik785hucw.fsf@melbourne.laas.fr>
>>>>> "bl" == Bj�rn Lindberg <·······@nada.kth.se> writes:

  bl> I get the following error in the window where I started the server:
  bl> 
  bl> 4206 ·····@nex:~/src/socket> server /tmp/socket
  bl> (null)
  bl> Memory fault

  > http://www.advancedlinuxprogramming.com/listings/chapter-5/socket-server.c

    /* Free the buffer.  */
    free (text);
    /* If the client sent the message "quit", we're all done.  */
    if (!strcmp (text, "quit"))
      return 1;

we need an internet-wide garbage collector. 

-- 
Eric Marsden                          <URL:http://www.laas.fr/~emarsden/>
From: Björn Lindberg
Subject: Re: Can I connect to a local socket?
Date: 
Message-ID: <hcs65joj08z.fsf@knatte.nada.kth.se>
Eric Marsden <········@laas.fr> writes:

> >>>>> "bl" == Bj�rn Lindberg <·······@nada.kth.se> writes:
> 
>   bl> I get the following error in the window where I started the server:
>   bl> 
>   bl> 4206 ·····@nex:~/src/socket> server /tmp/socket
>   bl> (null)
>   bl> Memory fault
> 
>   > http://www.advancedlinuxprogramming.com/listings/chapter-5/socket-server.c
> 
>     /* Free the buffer.  */
>     free (text);
>     /* If the client sent the message "quit", we're all done.  */
>     if (!strcmp (text, "quit"))
>       return 1;
> 
> we need an internet-wide garbage collector. 

Hehe, yep, that is an error in the server code.

I've found my error now, and it is embarrassingly simple. I simply
didn't look close enough at the C code to realise the protocol the
server implements. I have to first send the length of the string as a
C integer. Now I only have to figure out how to do that in CMUCL. I
tried setting the stream element-type to unsigned-byte and using
write-byte on it, but it doesn't seem to work. I know I could probably
solve it better by changing the protocol, but now I am curious on how
to get this to work. How do I send a 32-bit binary integer from Lisp?


Bj�rn
From: Thomas F. Burdick
Subject: Re: Can I connect to a local socket?
Date: 
Message-ID: <xcvwuc4puh7.fsf@famine.OCF.Berkeley.EDU>
·······@nada.kth.se (Bj�rn Lindberg) writes:

> Eric Marsden <········@laas.fr> writes:
> 
> > >>>>> "bl" == Bj�rn Lindberg <·······@nada.kth.se> writes:
> > 
> >   bl> I get the following error in the window where I started the server:
> >   bl> 
> >   bl> 4206 ·····@nex:~/src/socket> server /tmp/socket
> >   bl> (null)
> >   bl> Memory fault
> > 
> >   > http://www.advancedlinuxprogramming.com/listings/chapter-5/socket-server.c
> > 
> >     /* Free the buffer.  */
> >     free (text);
> >     /* If the client sent the message "quit", we're all done.  */
> >     if (!strcmp (text, "quit"))
> >       return 1;
> > 
> > we need an internet-wide garbage collector. 
> 
> Hehe, yep, that is an error in the server code.
> 
> I've found my error now, and it is embarrassingly simple. I simply
> didn't look close enough at the C code to realise the protocol the
> server implements. I have to first send the length of the string as a
> C integer. Now I only have to figure out how to do that in CMUCL. I
> tried setting the stream element-type to unsigned-byte and using
> write-byte on it, but it doesn't seem to work. I know I could probably
> solve it better by changing the protocol, but now I am curious on how
> to get this to work. How do I send a 32-bit binary integer from Lisp?

Using LDB and WRITE-BYTE.  Be sure to send your octets in the expected
order (big-endian or little-endian).  I have the following util
functions to help with this:

  *ENDIANNESS*
    Controls the endianness of wide-byte I/O.
    Should be :BIG or :LITTLE.

  READ-BYTE* (width stream &optional (eof-errorp t) eof-value)
    Read an unsigned byte of WIDTH bits from STREAM.
    WIDTH should be an even multiple of 8.

  WRITE-BYTE* (uint width stream)
    Write an unsigned byte of WIDTH bits to STREAM.
    Again with the even multiple of 8 thing.

  AS-TWOS-COMPLIMENT (uint width)
    Interpret the unsigned integer UINT as a string of bits encoding
    a twos-compliment number of WIDTH bits.  Return the appropriate
    signed integer.

  AS-BIT-VECTOR (uint width)

-- 
           /|_     .-----------------------.                        
         ,'  .\  / | No to Imperialist war |                        
     ,--'    _,'   | Wage class war!       |                        
    /       /      `-----------------------'                        
   (   -.  |                               
   |     ) |                               
  (`-.  '--.)                              
   `. )----'                               
From: Charlie
Subject: Re: Can I connect to a local socket?
Date: 
Message-ID: <bkf63r$t5l0$1@ID-155962.news.uni-berlin.de>
I used this in CLISP:

(defun write-int (int str)
   (write-byte (ldb (byte 8 0) int) str)
   (write-byte (ldb (byte 8 8) int) str)
   (write-byte (ldb (byte 8 16) int) str)
   (write-byte (ldb (byte 8 24) int) str))

(defun test-connection ()
   (let ((sock (socket:socket-connect 7777 "127.0.0.1"
				     :element-type '(unsigned-byte 8))))
     (write-byte (char-code #\A) sock)
     (write-int -5555555 sock)))


NB the element-type of the socket is (unsigned-byte 8) == unsigned char in C


Bj�rn Lindberg wrote:

> Eric Marsden <········@laas.fr> writes:
> 
> 
>>>>>>>"bl" == Bj�rn Lindberg <·······@nada.kth.se> writes:
>>
>>  bl> I get the following error in the window where I started the server:
>>  bl> 
>>  bl> 4206 ·····@nex:~/src/socket> server /tmp/socket
>>  bl> (null)
>>  bl> Memory fault
>>
>>  > http://www.advancedlinuxprogramming.com/listings/chapter-5/socket-server.c
>>
>>    /* Free the buffer.  */
>>    free (text);
>>    /* If the client sent the message "quit", we're all done.  */
>>    if (!strcmp (text, "quit"))
>>      return 1;
>>
>>we need an internet-wide garbage collector. 
> 
> 
> Hehe, yep, that is an error in the server code.
> 
> I've found my error now, and it is embarrassingly simple. I simply
> didn't look close enough at the C code to realise the protocol the
> server implements. I have to first send the length of the string as a
> C integer. Now I only have to figure out how to do that in CMUCL. I
> tried setting the stream element-type to unsigned-byte and using
> write-byte on it, but it doesn't seem to work. I know I could probably
> solve it better by changing the protocol, but now I am curious on how
> to get this to work. How do I send a 32-bit binary integer from Lisp?
> 
> 
> Bj�rn
From: Charlie Burrows
Subject: Re: Can I connect to a local socket?
Date: 
Message-ID: <bkf6bo$156b3$1@ID-155962.news.uni-berlin.de>
I used this in CLISP (slightly modified):

(defun write-int (int str)
   (write-byte (ldb (byte 8 0) int) str)
   (write-byte (ldb (byte 8 8) int) str)
   (write-byte (ldb (byte 8 16) int) str)
   (write-byte (ldb (byte 8 24) int) str))

(defun test-connection ()
   (let ((sock (socket:socket-connect 7777 "127.0.0.1"
				     :element-type '(unsigned-byte 8))))
     (write-byte 4 sock) ;; Sorry my mistake
     (write-int -5555555 sock)))


NB the element-type of the socket is (unsigned-byte 8) == unsigned char
in C.


Bj�rn Lindberg wrote:

> Eric Marsden <········@laas.fr> writes:
> 
> 
>>>>>>>"bl" == Bj�rn Lindberg <·······@nada.kth.se> writes:
>>
>>  bl> I get the following error in the window where I started the server:
>>  bl> 
>>  bl> 4206 ·····@nex:~/src/socket> server /tmp/socket
>>  bl> (null)
>>  bl> Memory fault
>>
>>  > http://www.advancedlinuxprogramming.com/listings/chapter-5/socket-server.c
>>
>>    /* Free the buffer.  */
>>    free (text);
>>    /* If the client sent the message "quit", we're all done.  */
>>    if (!strcmp (text, "quit"))
>>      return 1;
>>
>>we need an internet-wide garbage collector. 
> 
> 
> Hehe, yep, that is an error in the server code.
> 
> I've found my error now, and it is embarrassingly simple. I simply
> didn't look close enough at the C code to realise the protocol the
> server implements. I have to first send the length of the string as a
> C integer. Now I only have to figure out how to do that in CMUCL. I
> tried setting the stream element-type to unsigned-byte and using
> write-byte on it, but it doesn't seem to work. I know I could probably
> solve it better by changing the protocol, but now I am curious on how
> to get this to work. How do I send a 32-bit binary integer from Lisp?
> 
> 
> Bj�rn
From: Björn Lindberg
Subject: Re: Can I connect to a local socket?
Date: 
Message-ID: <hcs8yojnngo.fsf@tjatte.nada.kth.se>
Charlie Burrows <···············@riskdecisions.com> writes:

> I used this in CLISP (slightly modified):
> 
> (defun write-int (int str)
>    (write-byte (ldb (byte 8 0) int) str)
>    (write-byte (ldb (byte 8 8) int) str)
>    (write-byte (ldb (byte 8 16) int) str)
>    (write-byte (ldb (byte 8 24) int) str))
> 
> (defun test-connection ()
>    (let ((sock (socket:socket-connect 7777 "127.0.0.1"
> 				     :element-type '(unsigned-byte 8))))
>      (write-byte 4 sock) ;; Sorry my mistake
>      (write-int -5555555 sock)))
> 
> 
> NB the element-type of the socket is (unsigned-byte 8) == unsigned char
> in C.

Did you ever get it to work with the server as written though? It
seems that the server read() only blocks until there is anything to
read at all, but returns as soon as it has read something even if it
is not the asked for number of bytes. (This is all probably obvious to
anyone who knows anything about sockets, ie not me :-) So it seems
that with the server as written, the client has to make two sends, no
more and no less. The length has to be sent in one piece, and then the
message with a terminating zero. I tried it in python, and got it to
work:

s = socket.socket(socket.AF_UNIX, socket.SOCK_STREAM)
s.connect("/tmp/socket")
s.send("\x07\x00\x00\x00")
s.send("PYTHON\x00")
s.close()

I could do the same in lisp, except that I don't know how to get a
null byte in a string. Is there some format tilde-modifier that would
allow me to do that? Here is my code:

(defun send-message (message)
  (let* ((socket (ext:connect-to-unix-socket "/tmp/socket"))
	 (stream (sys:make-fd-stream socket
				     :input t
				     :output t
				     :element-type '(unsigned-byte 8)
				     :buffering :none)))
    (write-byte (ldb (byte 32 0) (1+ (length message))) stream)
    (format stream message)
    (ext:close-socket socket)))

(I realise that the server code is very simplistic, and should be more
robustly written anyway. It is just out of perverse interest that I
want to get this to work with it as written.)


Bj�rn
From: Daniel Barlow
Subject: Re: Can I connect to a local socket?
Date: 
Message-ID: <87oexf3pia.fsf@noetbook.telent.net>
·······@nada.kth.se (Bj�rn Lindberg) writes:

> Did you ever get it to work with the server as written though? It
> seems that the server read() only blocks until there is anything to
> read at all, but returns as soon as it has read something even if it
> is not the asked for number of bytes. (This is all probably obvious to
> anyone who knows anything about sockets, ie not me :-) So it seems

This is what read() does, yes.  If that's Advanced, God help all of us
who have to use code written by Average Linux Programers.

> that with the server as written, the client has to make two sends, no
> more and no less. The length has to be sent in one piece, and then the
> message with a terminating zero. I tried it in python, and got it to
> work:

Almost.  You could do the whole thing in a single write: the first
read() done by the server only reads (sizeof length) - probably 4 -
bytes.  The remainder of the buffer will sit there for the next read.

> (defun send-message (message)
>   (let* ((socket (ext:connect-to-unix-socket "/tmp/socket"))
> 	 (stream (sys:make-fd-stream socket
> 				     :input t
> 				     :output t
> 				     :element-type '(unsigned-byte 8)
> 				     :buffering :none)))
>     (write-byte (ldb (byte 32 0) (1+ (length message))) stream)
>     (format stream message)
>     (ext:close-socket socket)))

Given this is CMUCL, the simplest way to get it to work is change
:buffering :none to :buffering :full, then it will only call write()
when the buffer is flushed explicitly (e.g. with CLOSE or FORCE-OUTPUT)
or runs out of space.  I think fd-stream buffers are 2 or 4k, which
should be plenty.

:buffering :none is also woefully slow if you use write-sequence on
the stream, at least in sbcl.  Haven't checked if that's common to
cmucl or not, it might be something we broke.


-dan

-- 

   http://www.cliki.net/ - Link farm for free CL-on-Unix resources 
From: Björn Lindberg
Subject: Re: Can I connect to a local socket?
Date: 
Message-ID: <hcs1xuaoo79.fsf@tjatte.nada.kth.se>
Daniel Barlow <···@telent.net> writes:

> ·······@nada.kth.se (Bj�rn Lindberg) writes:
> 
> > Did you ever get it to work with the server as written though? It
> > seems that the server read() only blocks until there is anything to
> > read at all, but returns as soon as it has read something even if it
> > is not the asked for number of bytes. (This is all probably obvious to
> > anyone who knows anything about sockets, ie not me :-) So it seems
> 
> This is what read() does, yes.  If that's Advanced, God help all of us
> who have to use code written by Average Linux Programers.

I'm not sure if this is a slight towards me or the book from which the
examples were taken. Speaking for me, I'll just say that I have not
done low-level socket programming in C before.

> > that with the server as written, the client has to make two sends, no
> > more and no less. The length has to be sent in one piece, and then the
> > message with a terminating zero. I tried it in python, and got it to
> > work:
> 
> Almost.  You could do the whole thing in a single write: the first
> read() done by the server only reads (sizeof length) - probably 4 -
> bytes.  The remainder of the buffer will sit there for the next read.

Yes, that is true of course. What I am wondering now (which is
slightly unrelated to the original issue, since the latter can be
resolved in a number of ways), out of curiousity, is if it is possible
to store a null value as a part of a lisp string, perhaps using
format?

> Given this is CMUCL, the simplest way to get it to work is change
> :buffering :none to :buffering :full, then it will only call write()
> when the buffer is flushed explicitly (e.g. with CLOSE or FORCE-OUTPUT)
> or runs out of space.  I think fd-stream buffers are 2 or 4k, which
> should be plenty.

What would be the simplest way if it was not CMUCL?


Bj�rn
From: Peter Seibel
Subject: Re: Can I connect to a local socket?
Date: 
Message-ID: <m3smmqlps2.fsf@javamonkey.com>
·······@nada.kth.se (Bj�rn Lindberg) writes:

> What I am wondering now (which is slightly unrelated to the original
> issue, since the latter can be resolved in a number of ways), out of
> curiousity, is if it is possible to store a null value as a part of
> a lisp string, perhaps using format?

Assuming you are using a Lisp implementation that uses ASCII or
Unicode as it's character encoding this will probably do what you
want:

  (format nil "this is a null terminated string~c" (code-char 0))

In some implementations (e.g. Allegro Common Lisp, CLISP, and SBCL)
you may also be able to refer to the null character by name:

  (format nil "this is a null terminated string~c" #\null)

-Peter

-- 
Peter Seibel                                      ·····@javamonkey.com

         Lisp is the red pill. -- John Fraser, comp.lang.lisp
From: Daniel Barlow
Subject: Re: Can I connect to a local socket?
Date: 
Message-ID: <87brte45t5.fsf@noetbook.telent.net>
·······@nada.kth.se (Bj�rn Lindberg) writes:

>> This is what read() does, yes.  If that's Advanced, God help all of us
>> who have to use code written by Average Linux Programers.
>
> I'm not sure if this is a slight towards me or the book from which the
> examples were taken. Speaking for me, I'll just say that I have not

The book, of course.  

> Yes, that is true of course. What I am wondering now (which is
> slightly unrelated to the original issue, since the latter can be
> resolved in a number of ways), out of curiousity, is if it is possible
> to store a null value as a part of a lisp string, perhaps using
> format?

I believe it's implementation-dependent: the only characters that a
conforming implementation _must_ support are those in the
standard-char repertoire, consisting of 94 graphic characters plus
space and newline.  See section 2.1.3 in ANSI.

If your implementation additionally supports some character repertoire
which includes a character with code 0 (and, let's face it, any
implementation that runs on a machine with Unix-domain sockets and
_doesn't_ support, say, ASCII, has some hard questions to answer),
then, yes, you can get it into a string just as you would any other
character.

* (let ((s (copy-seq "fooxbar"))) (setf (elt s 3) (code-char 0)) s)
·····@bar"
* (format nil "foo~Cbar" (code-char 0))
·····@bar"

>> Given this is CMUCL, the simplest way to get it to work is change
>> :buffering :none to :buffering :full, then it will only call write()
>
> What would be the simplest way if it was not CMUCL?

Depends what else it was.  Talking to unix-domain sockets is not in
the scope of ANSI.


-dan

-- 

   http://www.cliki.net/ - Link farm for free CL-on-Unix resources 
From: Charlie
Subject: Re: Can I connect to a local socket?
Date: 
Message-ID: <bkf3ju$12j2j$1@ID-155962.news.uni-berlin.de>
It also expects you to send the length of the transmission in bytes 
before you send the text. Read the source carefully and you'll find that 
there is alot of superfluous and wildly incorrect bits in it. I ended up 
re-writing most of it for testing with clisp because it just wasn't what 
I needed (and I had to switch it to internet sockets).
I can send you the modified C if you want but as I said it doesn't use 
local (unix) sockets anymore.

Bj�rn Lindberg wrote:

> Charlie <·····@nowhere.co.uk> writes:
> 
> 
>>Hi,
>>	I've got a local socket server in C and I'm trying to get my clisp to
>>connect to it but as it's a local socket it doesn't seem to have a port
>>number so I can't use (socket:socket-connect).
>>	I have also tried to open the socket file as a file with:
>>
>>(with-open-file (sock (merge-pathnames (user-home-pathname) "test"))
>>	:direction :output
>>	:element-type 'character)
>>	(loop for i from - to 100
>>		do (write-char #\A)))
>>
>>but I get "UNIX error 6 (ENXIO): no such device or address" presumably
>>because the socket is not a "proper" file.
>>The socket file is called test and in the expected place.
>>
>>Can anyone tell me the correct approach?
>>
>>The C code for the server is from
>>http://www.advancedlinuxprogramming.com/listings/chapter-5/socket-server.c
>>and all it does it listen, echo and quit on command.
> 
> 
> I got interested, and tried to write the client program in CMUCL, but
> I cannot get it to work either. This is my code:
> 
> (defun send-message (message)
>   (let* ((socket (ext:connect-to-unix-socket "/tmp/socket"))
>          (stream (sys:make-fd-stream socket
>                                      :input t
>                                      :output t
>                                      :buffering :none)))
>     (format stream message)))
> 
> (send-message "hello there!")
> 
> I get the following error in the window where I started the server:
> 
> 4206 ·····@nex:~/src/socket> server /tmp/socket
> (null)
> Memory fault
> 
> The C client program works well. Does anyone know what is wrong?
> 
> 
> Bjorn