@c =================================================================== @c
@c    serrano/prgm/project/bigloo/manuals/socket.texi                  @c
@c    ------------------------------------------------------------     @c
@c    Author      :  Manuel Serrano                                    @c
@c    Creation    :  Tue Jun 30 08:09:52 1998                          @c
@c    Last change :  Mon Jan  7 10:47:50 2002 (serrano)                @c
@c    ------------------------------------------------------------     @c
@c    Socket support                                                   @c
@c =================================================================== @c

@c ------------------------------------------------------------------- @c
@c    Socket support                                                   @c
@c ------------------------------------------------------------------- @c
@node Socket, , Process, System Programming
@comment  node-name,  next,  previous,  up
@section Socket support
@cindex Socket support

Bigloo defines sockets, on systems that support them, as first class objects.
Sockets permits processes to communicate even if they are on different 
machines. Sockets are useful for creating client-server applications.
The implementation and this documentation are, to a great
extent copies of the STk [Gallesio95] socket support.

@deffn {bigloo procedure} make-client-socket hostname port-number [buffered]
@cindex unbufferized socket port

@code{make-client-socket} returns a new socket object. This socket establishes
a link between the running application listening on port @var{port-number}
of @var{hostname}. If optional argument @code{buffered} is @code{#f} then
the input port associated with the socket is unbuffered. This is useful for
socket clients connected to servers that do not emit #\Newline character 
after emissions. If optional argument @code{buffered} is missing or is not
to @code{#f} the input port uses a buffer.

When a socket is used in unbufferized mode the characters available on
the input port @emph{must} be read exclusively with @code{read-char}
or @code{read-line}. It is forbidden to use @code{read} or any regular
grammar.  This limitation is imposed by Rgc (see @ref{Regular Parsing}) that
intrinsicly associate buffers with regular grammars. If the current Rgc
implementation is improved on the coming version this restriction will
be suppressed.
@end deffn

@deffn {bigloo procedure} socket? obj
@deffnx {bigloo procedure} socket-server? obj
@deffnx {bigloo procedure} socket-client? obj
Returns @code{#t} if @var{obj} is a socket, a socket server a socket client.
Otherwise returns @code{#f}. Socket servers and socket clients are
sockets.
@end deffn

@deffn {bigloo procedure} socket-hostname socket
Returns a string which contains the name of the distant host attached to  
@var{socket}. If @var{socket} has been created with @code{make-client-socket}
this procedure returns the official name of the distant machine used for 
connection. If @var{socket} has been created with @code{make-server-socket},
this function returns the official name of the client connected to the socket. 
If no client has used yet the socket, this function returns @code{#f}.
@end deffn

@deffn {bigloo procedure} socket-host-address socket
@cindex @w{IP number}
Returns a string which contains the IP number of
the distant host attached to @var{socket}. If @var{socket} has been
created with @code{make-client-socket} this procedure returns the
IP number of the distant machine used for connection. If
@var{socket} has been created with @code{make-server-socket}, this
function returns the address of the client connected to the
socket.  If no client has used yet the socket, this function returns
@code{#f}.
@end deffn

@deffn {bigloo procedure} socket-local-address socket
@cindex @w{IP number}
Returns a string which contains the IP number of
the local host attached to @var{socket}.
@end deffn


@deffn {bigloo procedure} socket-port-number socket
Returns the integer number of the port used for @var{socket}.
@end deffn

@deffn {bigloo procedure} socket-input socket
@deffnx {bigloo procedure} socket-output socket

Returns the file port associated for reading or writing with the program 
connected with @var{socket}. If no connection has already been established,
these functions return @code{#f}.

The following example shows how to make a client socket. Here we create a
socket on port 13 of the machine ``@code{kaolin.unice.fr}''@footnote{Port 13
is generally used for testing: making a connection to it permits to know
the distant system's idea of the time of day.}:
@smalllisp
(let ((s (make-client-socket "kaolin.unice.fr" 13)))
  (print "Time is: " (read-line (socket-input s)))
  (socket-shutdown  s))
@end smalllisp
@end deffn

@deffn {bigloo procedure} make-server-socket [port-number]
@code{make-server-socket} returns a new socket object. If @var{port-number}
is specified, the socket is listening on the specified port; otherwise, the
communication port is choosen by the system. 
@end deffn

@deffn {bigloo procedure} socket-accept socket [buffered]
The function @code{socket-accept} replaces the former Bigloo functions
@code{socket-accept-connection} and @code{socket-dup}.
@code{socket-accept} waits for a client connection on the given
@var{socket}. It returns a @code{client-socket}.  If no client is
already waiting for a connection, this procedure blocks its caller;
otherwise, the first connection request on the queue of pending
connections is connected to @var{socket}. This procedure must be
called on a server socket created with @code{make-server-socket}.  If
optional argument @code{buffered} is @code{#f} then the input port
associated with the socket is unbuffered. This is useful for socket
clients connected to servers that do not emit #\Newline character
after emissions. If optional argument @code{buffered} is missing or is
not to @code{#f} the input port uses a buffer. The result of
@code{socket-accept} is undefined.

@emph{Note:} When a socket is used in unbufferized mode the characters
available on the input port @emph{must} be read exclusively with
@code{read-char} or @code{read-line}. It is forbidden to use @code{read}
or any regular grammar.  This limitation is imposed by Rgc (see
@ref{Regular Parsing}) that intrinsicly associate buffers with regular
grammars. If the current Rgc implementation is improved on the coming
version this restriction will be suppressed.

The following exemple is a simple server which waits for a connection
on the port 1234@footnote{Under Unix, you can simply connect to
  listening socket with the @code{telnet} command. With the given
  example, this can be
  achived by typing the following command in a window shell:
  @code{$ telnet localhost 1234}}. Once the connection with the
distant program is established, we read a line on the input port
associated to the socket and we write the length of this line on its
output port.
@smalllisp
(let* ((s (make-server-socket 1234))
       (s2 (socket-accept s)))
  (let ((l (read-line (socket-input s2))))
    (fprint (socket-output s) "Length is: " (string-length l))
    (flush-output-port (socket-output s2)))
  (socket-close s)
  (socket-shutdown s))
@end smalllisp
@end deffn

@deffn {bigloo procedure} socket-accept-connection socket [buffered]
@code{socket-accept-connection} waits for a client connection on the
given @var{socket}. If no client is already waiting for a connection,
this procedure blocks its caller; otherwise, the first connection
request on the queue of pending connections is connected to
@var{socket}.  

@emph{note:}This function is part of the old Bigloo API. It was
intended to be used in conjunction with
@code{socket-accept-connection}. The new API made of
@code{socket-accept} and @code{socket-close} should be preferred.

This procedure must be called on a server socket created
with @code{make-server-socket}.  If optional argument @code{buffered} is
@code{#f} then the input port associated with the socket is
unbuffered. This is useful for socket clients connected to servers that
do not emit #\Newline character after emissions. If optional argument
@code{buffered} is missing or is not to @code{#f} the input port uses a
buffer. The result of @code{socket-accept-connection} is undefined.

@emph{Note:} When a socket is used in unbufferized mode the characters
available on the input port @emph{must} be read exclusively with
@code{read-char} or @code{read-line}. It is forbidden to use @code{read}
or any regular grammar.  This limitation is imposed by Rgc (see
@ref{Regular Parsing}) that intrinsicly associate buffers with regular
grammars. If the current Rgc implementation is improved on the coming
version this restriction will be suppressed.

The following exemple is a simple server which waits for a connection
on the port 1234@footnote{Under Unix, you can simply connect to
  listening socket with the @code{telnet} command. With the given
  example, this can be
  achived by typing the following command in a window shell:
  @code{$ telnet localhost 1234}}. Once the connection with the
distant program is established, we read a line on the input port
associated to the socket and we write the length of this line on its
output port.
@smalllisp
(let ((s (make-server-socket 1234)))
  (socket-accept-connection s)
  (let ((l (read-line (socket-input s))))
    (fprint (socket-output s) "Length is: " (string-length l))
    (flush-output-port (socket-output s)))
  (socket-shutdown s))
@end smalllisp
@end deffn

@deffn {bigloo procedure} socket-close socket
The function @code{socket-close} closes the connection established with
a @code{socket-client}.
@end deffn

@deffn {bigloo procedure} socket-shutdown socket [close]
@code{Socket-shutdown} shutdowns the connection associated to @var{socket}.
@var{Close} is a boolean; it indicates if the socket must be closed or not, 
when the connection is destroyed. Closing the socket forbids further 
connections on the same port with the @code{socket-accept-connection} 
procedure. Omitting a value for @var{close} implies the closing of socket.
The result of @code{socket-shutdown} is undefined. 

The following example shows a simple server: when there is a new connection
on the port number 1234, the server displays the first line sent to it by the
client, discards the others and go back waiting for further client connections.
@smalllisp
(let ((s (make-server-socket 1234)))
  (let loop ()
    (socket-accept-connection s)
    (print "I've read: " (read-line (socket-input s)))
    (socket-shutdown s #f)
    (loop)))
@end smalllisp
@end deffn

@deffn {bigloo procedure} socket-down? socket
Returns @code{#t} if @var{socket} has been previously closed 
with @code{socket-shutdown}. It returns @code{#f} otherwise.
@end deffn

@deffn {bigloo procedure} socket-dup socket

Returns a copy of @var{socket}. 

@emph{note:}This function is part of the old Bigloo
API. It was intended to be used in conjunction with 
@code{socket-accept-connection}. The new API made of @code{socket-accept}
and @code{socket-close} should be preferred.

The original and the copy socket can be used interchangeably. However,
if a new connection is accepted on one socket, the characters
exchanged on this socket are not visible on the other socket.
Duplicating a socket is useful when a server must accept multiple
simultaneous connections.  The following example creates a server
listening on port 1234. This server is duplicated and, once two
clients are present, a message is sent on both connections.
@smalllisp
(define s1 (make-server-socket 1234))
(define s2 (socket-dup s1))
(socket-accept-connection s1)
(socket-accept-connection s2)
;; blocks until two clients are present
(display #"Hello,\n" (socket-output s1))
(display #"world\n"  (socket-output s2))
(flush-output-port (socket-output s1))
(flush-output-port (socket-output s2))
@end smalllisp
@end deffn

Here is another example of making use of sockets:

@smalllisp
(define s1 (make-server-socket))
(define s2 #unspecified)

(dynamic-wind 
   ;; Init: Launch an xterm with telnet running
   ;; on the s listening port and connect
   (lambda ()
      (run-process "/usr/X11R6/bin/xterm" "-display" ":0" "-e" "telnet" "localhost" 
		   (number->string (socket-port-number s1)))
      (set! s2 (socket-accept s1))
      (display #"\nWelcome on the socket REPL.\n\n> " (socket-output s2))
      (flush-output-port (socket-output s2)))

   ;; Action: A toplevel like loop
   (lambda ()
      (let loop ()
	 (let ((obj (eval (read (socket-input s2)))))
	    (fprint (socket-output s2) "; Result: " obj)
	    (display "> " (socket-output s2))
	    (flush-output-port (socket-output s2))
	    (loop))))

   ;; Termination: We go here when 
   ;;     -a: an error occurs 
   ;;     -b: connection is closed
   (lambda ()
      (print #"Shutdown ......\n")
      (socket-close s2)
      (socket-shutdown s1)))
@end smalllisp

Here is a second example that uses sockets. It implements
a client-server architecture and it uses unbufferized
(see @code{socket-accept}) input ports.
@cindex client-server

First, here is the code of the client:

@smalllisp
(module client)

(let* ((s (make-client-socket "localhost" 8080 #f))
       (p (socket-output s)))
   (display "string" p)
   (newline p)
   (display "abc" p)
   (flush-output-port p)
   (let loop ()
      (loop)))
@end smalllisp

Then, here is the code of the server:

@smalllisp
(module server)

(let* ((s (make-server-socket 8080))
       (s2 (socket-accept s #f)))
   (let ((pin (socket-input s2)))
      (let loop ()
         (display (read-char pin))
         (flush-output-port (current-output-port))
         (loop))))
@end smalllisp

At, to conclude here the source code for a server waiting for multiple
consecutive connections:

@smalllisp
(define (main argv)
   (let ((n (if (pair? (cdr argv))
                (string->integer (cadr argv))
                10))
	 (s (make-server-socket)))
      (print "s: " s)
      (let loop ((i 0))
         (if (<fx i n)
             (let ((s2 (socket-accept s)))
		(print "i: " i " " s2)
		(print (read-line (socket-input s2)))
		(socket-close s2)
                (loop (+fx i 1)))
	     (socket-shutdown s)))))
@end smalllisp
