@c -*-texinfo-*-

@node Tcp, Mailboxes, Builtin Predicates, Top
@comment  node-name,  next,  previous,  up
@chapter TCP Interface 
@menu
* TcpIntro::                    Introduction to TCP/IP
* TcpConnected::                Connection Oriented Protocol
* TcpConnectionless::           Connectionless Oriented Protocol
* TcpMisc::                     Miscellaneous TCP Predicates
* TcpLow::                      Low Level TCP primitives
* TcpEg::                       Simple TCP Examples
@end menu

To allow for the communication between different ICP processes, a TCP 
interface is provided. To make the interface accessible to users who are 
not experts at TCP and or socket level programming, we provide a 
restricted subset of the full TCP functionality provided at the C level. 
The intention was that simple communication can be written quickly 
without knowledge of the underlying communication protocol.

The primitives described here are implemented for both the Prolog and
Parlog sub-systems in ICP.
The TCP interface is not part of the core ICP system and must be loaded
by a command of the form
@example
?- ensure_loaded(tcp).
@end example
The Prolog and Parlog interfaces are distinct libraries and so must
be loaded separately.

@node TcpIntro, TcpConnected,  , Tcp
@comment  node-name,  next,  previous,  up
@section Introduction to TCP/IP

It is beyond the scope of this manual to give a full description of the
TCP/IP communication protocol. For details the reader is refered to
@cite{Unix Network Programming} by W. Richard Stevens and to the Unix
documentation.

In TCP communications happen through @dfn{sockets} which are similar to 
file handles used in file I/O. Inter-process communication occurs
between two @dfn{peers}; the source and destination addresses. An
address consists of two components

@table @dfn
@item network address
This specifies the IP address of the machine
@item port
This allows multiple peers on a given machine
@end table

There are essentially two means of communication supported under the TCP
protocol, @dfn{connection} and @dfn{connectionless}.

@node TcpConnected, TcpConnectionless, TcpIntro, Tcp
@comment  node-name,  next,  previous,  up
@section Connection Oriented Protocol

A socket is created and @dfn{bound} to a particular @dfn{port} and
@dfn{host address}. The host address indicates the machine with
which to communicate. Typically a single process on any one machine will
listen for data on a particular port. Once a socket has been bound,
subsequent reads on this socket do not require the specification of the
source of the data (tcp_send/2, tcp_send/3).
A connected server will typically have the following form
@example
   ...,
   tcp_server(Port, Socket),            % open and bind socket
   tcp_accept(Socket, NewSocket),       % accept connection
   tcp_recv(NewSocket, Term1),          % read from connection
   ...,
   tcp_send(NewSocket, Term2),          % write to connection
   ...,
   tcp_close(NewSocket),                % close connection
   ...,                                 % here could do more accepts
   tcp_close(Socket).                   % close socket
@end example
The corresponding clients which connect to the server would have the 
following form
@example
   ...,
   tcp_client(Port, Address, Socket),   % connect to server address and port
   tcp_send(Socket, Term1),             % send data to server
   ...,
   tcp_recv(Socket, Term2),             % receive data from server
   ...,
   tcp_close(Socket).
@end example

@table @code
@item tcp_server(@var{+Port}, @var{-Socket})
@itemx tcp_server(@var{+Port}, @var{-Socket}, @var{+Address})
@findex tcp_server/2
@findex tcp_server/3
This predicate may be used to initiate a connection-oriented server. It
is defined as
@example
tcp_server(Port, Socket) :-
        tcp_open(connection, Socket),
        tcp_bind(Socket, Port),
        tcp_listen(Socket).
@end example
The three argument form passes the extra argument to @code{tcp_bind/3}.

@item tcp_client(@var{+Port}, @var{+Address}, @var{-Socket})
@itemx tcp_client(@var{+Port}, @var{+Address}, @var{-Socket}, @var{+TimeOut})
@findex tcp_client/3
@findex tcp_client/4
This predicate may be used to initiate a connection-oriented client. It
is defined as
@example
tcp_client(Port, Address, Socket, TimeOut) :-
        tcp_open(connection, Socket),
        tcp_connect(Socket, Port, Address, TimeOut).
@end example
See @code{tcp_connect/4} for details about the arguments.

@item tcp_accept(@var{+Socket}, @var{-NewSocket})
@itemx tcp_accept(@var{+Socket}, @var{-NewSocket}, @var{-Port}, @var{-Address})
@itemx tcp_accept(@var{+Socket}, @var{-NewSocket}, @var{-Port}, @var{-Address}, @var{+TimeOut})
@findex tcp_accept/2
@findex tcp_accept/4
@findex tcp_accept/5
In the case of the server in a connection oriented protocol after
listening, the socket must accept connections from clients. This
returns a new socket @var{NewSocket} through which communication with
the client specified by @var{Address} and @var{Port} can proceed.  This
is equivalent to the C fragment
@example
@{
        struct sockaddr_in add;
        int socket=Socket, newsocket=NewSocket;
        int length=sizeof(struct sockaddr_in);

        newsocket = accept(socket,(struct sockaddr *) &add,
                &length);
        Address = ntohl(add.sin_addr.s_addr);
        Port = ntohs(add.sin_port);
@}
@end example
The variable @var{TimeOut} must have one of the values

@table @code
@item block
The call will block until a connection is established 
@item poll
This throws error 702 if immediate connection is not possible. By
default this error simply fails but a user defined error handler can
override this.
@item @var{Integer}
The call will block for @var{Integer} seconds after which if no
connection is established error 702 is thrown.
@end table

@item tcp_send(@var{+Socket}, @var{+Term})
@itemx tcp_send(@var{+Socket}, @var{+Term}, @var{+EFlag})
@findex tcp_send/2
@findex tcp_send/3
This is used to send data on a connected socket. It can not be used for
connectionless protocols as it does not specify the address of the
recipient.
@var{Eflag} must be one of the following atoms

@table @code
@item normal
Normal data in encoded form
@item raw
Normal data. Suitable for communication with non prolog
processes. Raw data must be a prolog atom.
@end table

@item tcp_recv(@var{+Socket}, @var{-Term})
@itemx tcp_recv(@var{+Socket}, @var{-Term}, @var{+EFlag})
@itemx tcp_recv(@var{+Socket}, @var{-Term}, @var{+EFlag}, @var{+TimeOut})
@findex tcp_recv/2
@findex tcp_recv/3
@findex tcp_recv/4
Is used to receive data from a socket. The variable @var{+Timeout} must
have one of the values

@table @code
@item block
The call will block until a connection is established 
@item poll
This throws error 702 if immediate connection is not possible. By
default this error simply fails but a user defined error handler can
override this.
@item @var{Integer}
The call will block for @var{Integer} seconds after which if no
connection is established error 702 is thrown.
@end table

@code{tcp_recv/2} is equivalent to the following definition
@example
tcp_recv(Socket, Term) :-
        tcp_recv(Socket, Term, normal, block).
@end example
@var{Eflag} must be one of the following atoms

@table @code
@item normal
Normal data in encoded form
@item raw
Normal data. Suitable for communication with non prolog
processes. Raw data must be a prolog atom.
@item peek
Used to determine if there is normal data without removing it from the buffer.
@item peek_raw
Used to determine if there is raw data without removing it from the buffer.
@end table
@end table

@node TcpConnectionless, TcpMisc, TcpConnected, Tcp
@comment  node-name,  next,  previous,  up
@section Connectionless Oriented Protocol

Here the socket is not associated with any particular port or host 
address. Hence to send data, the destination port and host address 
must be specified (tcp_sendto/4, tcp_sendto/5)

An example of a connectionless server follows
@example
   tcp_connectionless(ServerPort, Socket),        % open socket
   tcp_recvfrom(Socket, Term1, Port, Machine),    % receive data from client
   ...,
   tcp_sendto(Socket, Term2, Port, Machine),      % send data to client
   ...,
   tcp_close(Socket).
@end example

@example
   tcp_connectionless(ClientPort, Socket),
   tcp_sendto(Socket, Term1, Port, Machine),      % send data to server
   ...,
   tcp_recvfrom(Socket, Term2, Port, Machine),    % receive data from server
   ...,
   tcp_close(Socket).
@end example

@table @code
@item tcp_connectionless(@var{+Port}, @var{-Socket})
@findex tcp_connectionless/2
This predicate may be used to initiate a connectionless server or client. It
is defined as
@example
tcp_connectionless(Port, Socket) :-
        tcp_open(connectionless, Socket),
        tcp_bind(Socket, Port).
@end example

@item tcp_broadcast(@var{+Port}, @var{-Socket})
@findex tcp_broadcast/2
This predicate may be used to initiate a broadcast socket. It
is defined as
@example
tcp_broadcast(Port, Socket) :-
        tcp_open(broadcast, Socket),
        tcp_bind(Socket, Port).
@end example
Typically, @var{Port} is specified as 0, which lets the system choose an
unused port number.

@item tcp_sendto(@var{+Socket}, @var{+Term}, @var{+Port}, @var{+Address})
@itemx tcp_sendto(@var{+Socket}, @var{+Term}, @var{+Port}, @var{+Address}, @var{+EFlag})
@findex tcp_sendto/4
@findex tcp_sendto/5
This is used to send data on either a connected or connectionless socket.

@var{Eflag} must be one of the following atoms

@table @code
@item normal
Normal data in encoded form
@item raw
Normal data. Suitable for communication with non prolog
processes. Raw data must be a prolog atom.
@end table

@item tcp_sendbr(@var{+Socket}, @var{+Term}, @var{+Port})
@itemx tcp_sendbr(@var{+Socket}, @var{+Term}, @var{+Port}, @var{+EFlag})
@findex tcp_sendbr/3
@findex tcp_sendbr/4
This broadcasts on the specified port. The socket must have been opened
in broadcast mode.

@var{Eflag} must be one of the following atoms

@table @code
@item normal
Normal data in encoded form
@item raw
Normal data. Suitable for communication with non prolog
processes. Raw data must be a prolog atom.
@end table

@item tcp_recvfrom(@var{+Socket}, @var{-Term}, @var{-Port}, @var{-Address})
@itemx tcp_recvfrom(@var{+Socket}, @var{-Term}, @var{-Port}, @var{-Address}, @var{+EFlag})
@itemx tcp_recvfrom(@var{+Socket}, @var{-Term}, @var{-Port}, @var{-Address}, @var{+EFlag}, @var{+TimeOut})
@findex tcp_recvfrom/4
@findex tcp_recvfrom/5
@findex tcp_recvfrom/6
Is used to receive data from a socket, also returning the IP
address and port of the sender. The variable @var{+Timeout} must have
one of the values

@table @code
@item block
The call will block until a connection is established 
@item poll
This throws error 702 if immediate connection is not possible. By
default this error simply fails but a user defined error handler can
override this.
@item @var{Integer}
The call will block for @var{Integer} seconds after which if no
connection is established error 702 is thrown.
@end table

@code{tcp_recvfrom/4} is equivalent to the following definition
@example
tcp_recvfrom(Socket, Term, Port, Address) :-
        tcp_recvfrom(Socket, Term, Port, Address, normal, block).
@end example
@var{Eflag} must be one of the following atoms

@table @code
@item normal
Normal data in encoded form
@item raw
Normal data. Suitable for communication with non prolog
processes. Raw data must be a prolog atom.
@item peek
Used to determine if there is data without removing it from the buffer. 
@end table
@end table

@node TcpMisc, TcpLow, TcpConnectionless, Tcp
@comment  node-name,  next,  previous,  up
@section Miscellaneous TCP Predicates

This section describes some useful TCP primitives which are not
restricted to either connection or connectionless protocols.
The are typically used to enquire about the state of the
communication channel.

@table @code
@item tcp_close(@var{+Socket})
@findex tcp_close/1
This predicate is used to close a socket obtained with one of the calls
@code{tcp_socket/3}, @code{tcp_open/2} or @code{tcp_accept/5}.

@item tcp_checkconn(@var{+Socket})
@findex tcp_checkconn/1
This predicate succeeds if the socket is ready to be written to and
fails if it is not.

@item tcp_checkrecv(@var{+Socket})
@itemx tcp_checkrecv(@var{+Socket}, @var{+EFlag})
@findex tcp_checkrecv/1
@findex tcp_checkrecv/2
This predicate succeeds if the socket is ready to be read from and fails
if it is not.

@item tcp_getsockaddr(@var{+Socket}, @var{-Port}, @var{-Address})
@findex tcp_getsockaddr/3
This predicate returns the IP address @var{Address} and port number
of this side of a socket.
@example
@cartouche
| ?- tcp_server(5569, Socket).            

Socket = 0 

| ?- tcp_getsockaddr(0, Port, Address).

Port = 5569 
Address = 2460554497

| ?- tcp_gethost(Name, Address).

Name = laotzu
Address = 2460554497 
@end cartouche
@end example

@item tcp_getpeeraddr(@var{+Socket}, @var{-Port}, @var{-Address})
@findex tcp_getpeeraddr/3
This predicate returns the IP address @var{Address} and port number
of the far side of a connected socket.
@example
@cartouche
| ?- tcp_server(5569, Socket).

Socket = 0

| ?- tcp_accept(1, NewSocket, NewPort, Address).

NewSocket = 1 
NewPort = 1108
Address = 2460554499

| ?- tcp_getpeeraddr(1, Port, Address).

Port = 1108
Address = 2460554499
@end cartouche
@end example

@item tcp_currenthost(@var{-Name}, @var{-Address})
@findex tcp_currenthost/2
Gets the name and address of the current host.
@example
@cartouche
| ?- tcp_currenthost(Name, Address).

Name = sophia
Address = 2460554499 
@end cartouche
@end example

@item tcp_gethost(@var{?Name}, @var{?Address})
@findex tcp_gethost/2
The machine of name @var{Name} has IP address @var{Address}.
The predicate is deterministic.
@example
@cartouche
| ?- tcp_gethost(laotzu, Address).

Address = 2460554497 

| ?- tcp_gethost(Name, 2460554497).

Name = laotzu

| ?- tcp_gethost('146.169.21.1', L).

L = 2460554497 

@end cartouche
@end example

@item tcp_getport(@var{?Name}, @var{?Protocol}, @var{?Port})
@findex tcp_getport/3
The named port @var{Name}, is on port @var{Port}, using protocol
@var{Protocol}. These values correspond to the entries in file
@kbd{/etc/services}. Valid modes of use are
@code{tcp_getport(@var{+Name},@var{?Protocol}, @var{?Port})}
and
@code{tcp_getport(@var{?Name}, @var{?Protocol}, @var{+Port})}.
@example
@cartouche
| ?- tcp_getport(login, Protocol, Port).

Protocol = tcp
Port = 513 

| ?- tcp_getport(Name, Protocol, 513).

Name = who
Protocol = udp 

| ?- tcp_getport(Name, tcp, 513).

Name = login 
@end cartouche
@end example
The predicate is deterministic; It only finds one port per name.

@item tcp_real_socket(@var{+Socket}, @var{-Handle})
@findex tcp_real_socket/2
Predicates which return socket identifiers (such as @code{tcp_open/2}
return integers >= 0 which are unique identifiers for the socket.  Given
a socked identifier @var{Socket}, @code{tcp_real_socket/2} returns the file
handle for the socket. This is useful if user defined predicates require
this descriptor.
@end table

@node TcpLow, TcpEg, TcpMisc, Tcp
@comment  node-name,  next,  previous,  up
@section Low Level TCP primitives

This section describes other less frequently used TCP primitives.
They are provided here for completeness.

@table @code
@item tcp_open(@var{+Type}, @var{-Socket})
@findex tcp_open/2
The predicate @code{tcp_open/2} is defined in terms of
@code{tcp_socket/3} providing a higher level method of openning sockets.
Opens a TCP connection of type @var{Type} returning the identifier
@var{Socket}.  @var{Type} is one of the following atoms

@table @code
@item connection
A connected socket is opened. This provides sequenced, reliable two-way
connection based byte streams. A stream socket must be in a connected
state before any data may be sent or received on it. A connection to
another socket is created with a @code{tcp_connect/4} call.  Once
connected, data may be transferred using @code{tcp_send/3} and
@code{tcp_recv/4} calls.  When a session has been completed a
@code{close/1} call may be performed.  This is equivalent to the C call
@example
sock = socket(AF_INET, SOCK_STREAM, IPPROTO_IP);
@end example
and is defined as
@example
tcp_open(connection, Socket) :-
        tcp_socket(sock_stream, ipproto_ip, Socket).
@end example
@item connectionless
A connectionless socket is opened. This provides unreliable messages of
a fixed (typically small) maximum length. Data may be transferred using
@code{tcp_sendto/5} and @code{tcp_recvfrom/5} calls.  This is equivalent
to the C call
@example
sock = socket(AF_INET, SOCK_DGRAM, IPPROTO_IP);
@end example
and is defined as
@example
tcp_open(connectionless, Socket) :-
        tcp_socket(sock_dgram, ipproto_ip, Socket).
@end example
@item broadcast
A broadcast socket is opened. This is a connectionless socket intended
for broadcasting messages to the local network. Messages written to such
a socket may be received by any machines listening on the local network.
These are connectionless, unreliable messages of a fixed (typically
small) maximum length. The messages will be delivered to all broadcast
endpoints in the network.  Data may be transferred using
@code{tcp_send/3} and @code{tcp_recvfrom/5} calls.  This is equivalent
to the C fragment
@example
@{
        int i = 1;
        sock = socket(AF_INET, SOCK_DGRAM, IPPROTO_IP);
        setsockopt(sock,SOL_SOCKET,SO_BROADCAST,&i,
                sizeof(int));
@}
@end example
and is defined as
@example
tcp_open(broadcast, Socket) :-
        tcp_socket(sock_dgram, ipproto_ip, Socket),
        tcp_setsockopt(Socket, so_broadcast, 1).
@end example
@end table

@item tcp_bind(@var{+Socket}, @var{+Port})
@itemx tcp_bind(@var{+Socket}, @var{+Port}, @var{+Address})
@findex tcp_bind/2
@findex tcp_bind/3
Once a socket has been opened by a call to @code{tcp_open/2} or
@code{tcp_socket/3}, and with the exception of a connected client, it
should be bound to a port and an IP address. Some ports - typically 1-1023
are reserved by the system. If @var{Port}=0 the system will assign an
available port. The predicate @code{tcp_getport/3} may be used to obtain the
port number of a port named in @kbd{/etc/services}.
This is an interface to @code{tcp_bind/3} and is defined as
@example
tcp_bind(Socket, Port) :- tcp_bind(Socket, Port, inaddr_any).
@end example
@code{tcp_bind/3} is as @code{tcp_bind/2} except that the variable
@var{Address} is either the atom @code{inaddr_any} or an IP address
(integer such as 2460554498, or the equivalent atom in dot notation
'146.169.21.2') of an ethernet interface of
the machine (obtained from the predicate @code{tcp_gethost/2}).  This is only
important for machines which have more than one ethernet interface.
Specifying an IP address means that
only messages on that network will be sent/received.
If @var{Address} is @code{inaddr_any} then all the interfaces are used by
default.
This is equivalent to the following C fragment.
@example
@{
        struct sockaddr_in server;
        u_long machine = Address
        u_short port = Port
        int socket = Socket;

        server.sin_family = AF_INET;
        server.sin_addr.s_addr = htonl(machine);
        server.sin_port = htons(port);
        bind(socket, (struct sockaddr *) &server, sizeof(server));
@}
@end example

@item tcp_connect(@var{+Socket}, @var{+Port}, @var{+Address})
@itemx tcp_connect(@var{+Socket}, @var{+Port}, @var{+Address}, @var{+TimeOut})
@findex tcp_connect/3
@findex tcp_connect/4
In the case of the client in a connection oriented protocol the socket
needs to be connected to the server.  The @var{Address} may be specified
as a machine name (e.g. confucius, or 'confucius.doc.ic.ac.uk'), or the
IP address in integer form (e.g. 2460554498) or an atom in dot notation form
(e.g. '146.169.21.2').

@code{tcp_connect/4} is equivalent to the C fragment
@example
@{
        struct sockaddr_in add;
        u_long machine=Address;
        u_short port=Port;
        int socket=Socket;

        add.sin_family = AF_INET;
        add.sin_addr.s_addr = htonl(machine);
        add.sin_port = htons(port);
        fcntl(socket, F_SETFL, FASYNC);
        connect(socket, (struct sockaddr *) &add, sizeof(add));
        fcntl(socket, F_SETFL, 0);
@}
@end example
The variable @var{TimeOut} must have one of the values

@table @code
@item block
The call will block until a connection is established 
@item poll
This throws error 702 if immediate connection is not possible. By
default this error simply fails but a user defined error handler can
override this.
@item @var{Integer}
The call will block for @var{Integer} seconds after which if no
connection is established error 702 is thrown.
@end table

@item tcp_listen(@var{+Socket})
@findex tcp_listen/1
In the case of the server in a connection oriented protocol after
opening, and binding a socket it must specify a backlog for incoming
connections from clients. The backlog size is 5.  It corresponds to the
C fragment:
@example
@{
        int socket=Socket;

        listen(socket, 5);
@}
@end example

@item tcp_socket(@var{+Type}, @var{+Protocol}, @var{-Socket})
@findex tcp_socket/3
This predicate is used to open a TCP socket. The variable @var{Type}
must be one of

@table @code
@item sock_stream
For use in connected (stream) communication
@item sock_dgram
For use in connectionless (datagram) communication
@item sock_raw
For use in raw communication
@end table

The variable @var{Protocol} must be one of

@table @code
@item ipproto_ip
Suitable for any @var{Type}
@item ipproto_udp
Suitable for @var{Type}=@code{sock_dgram}
@item ipproto_tcp
Suitable for @var{Type}=@code{sock_stream}
@item ipproto_icmp
Suitable for @var{Type}=@code{sock_raw}
@item ipproto_raw
Suitable for @var{Type}=@code{sock_raw}
@end table

The variable @var{Socket} is bound to an integer which can be used in
subsequent TCP operations.

@item tcp_setsockopt(@var{+Socket}, @var{+Optname}, @var{+Value})
@findex tcp_setsockopt/3
This predicate allows the setting of various options on sockets.  The
supported values of @var{Optname} are the following

@table @code
@item so_debug
turn on debugging info recording
@item so_reuseaddr
allow local address reuse
@item so_keepalive
keep connections alive
@item so_dontroute
just use interface addresses
@item so_broadcast
permit sending of broadcast msgs
@item so_oobinline
leave received OOB data in line
@item so_sndbuf
send buffer size
@item so_rcvbuf
receive buffer size
@item so_sndtimeo
send timeout
@item so_rcvtimeo
receive timeout
@end table

The call is an interface to the UNIX system call @kbd{setsockopt(2)} and
is equivalent to the following C fragment
@example
@{
        int val = Val, opt = Opt, sock = Sock;
        setsockopt(sock,SOL_SOCKET,opt,(char *)&val,sizeof(val));
@}
@end example

@item tcp_getsockopt(@var{+Socket}, @var{+Optname}, @var{+Value})
@findex tcp_getsockopt/3
This predicate allows the getting of various options on sockets.  The
supported values of @var{Optname} are the following

@table @code
@item so_debug
turn on debugging info recording
@item so_reuseaddr
allow local address reuse
@item so_keepalive
keep connections alive
@item so_broadcast
permit sending of broadcast msgs
@item so_oobinline
leave received OOB data in line
@item so_sndbuf
send buffer size
@item so_rcvbuf
receive buffer size
@item so_sndtimeo
send timeout
@item so_rcvtimeo
receive timeout
@item so_error
get error status and clear
@item so_type
get socket type
@end table

The call is an interface to the UNIX system call @kbd{getsockopt(2)} and
is equivalent to the following C fragment
@example
@{
        int val = Val, opt = Opt, sock = Sock;
        getsockopt(sock,SOL_SOCKET,opt,(char *)&val,sizeof(val));
@}
@end example
@end table

@node TcpEg,  , TcpLow, Tcp
@comment  node-name,  next,  previous,  up
@section Simple TCP Examples

@menu
* TcpEgConnected::              Connected Sockets
* TcpEgConnectionless::         Connectionless Sockets
* TcpEgBroadcast::              Broadcast Sockets
@end menu

@node TcpEgConnected, TcpEgConnectionless,  , TcpEg
@comment  node-name,  next,  previous,  up
@subsection Connected Sockets
The program below is an example of using the TCP connection protocol.  The
full source code can be found in the file
@file{$ICP_INSTALLDIR/examples/tcp/simple_connected.pl}.
A more sophisticated example is in file 
@file{$ICP_INSTALLDIR/examples/tcp/connected.pl}.

To run the example, two ICP processes should be started and the command
@example
@cartouche
| ?- server.
@end cartouche
@end example
run on one process while 
@example
@cartouche
| ?- client(Port, Address).
@end cartouche
@end example
is run on the other.  Input on the client is echoed by the server.

@example
/********************** connected server *************************/
server :-
    tcp_server(0, Socket),
    tcp_getsockaddr(Socket, Port, Address),
    write('use '), write(client(Port, Address)), write('.\n'),
    server_loop(ok, Socket).

server_loop(stop, Socket) :- !, tcp_close(Socket).
server_loop(_, Socket) :-
    tcp_accept(Socket, NewSocket),
    process_request(ok, NewSocket, T),
    server_loop(T, Socket).

process_request(stop, Socket, stop) :- !, tcp_close(Socket).
process_request(end, Socket, end) :- !, tcp_close(Socket).
process_request(_, Socket, Final) :-
    tcp_recv(Socket, T),
    writenl(tcp_recv(Socket, T)),
    process_request(T, Socket, Final).
process_request(_, Socket, end) :- !, tcp_close(Socket).

/*********************** connected client *************************/
client(Port, Address) :-
    tcp_client(Port, Address, Socket),
    client_loop(ok, Socket).

client_loop(stop, Socket) :- !, tcp_close(Socket).
client_loop(end, Socket) :- !, tcp_close(Socket).
client_loop(_, Socket) :-
    write('enter term, "end" ends this channel, "stop" stops server> '),
    flush,
    read(T),
    tcp_send(Socket, T),
    client_loop(T, Socket).
@end example

@node TcpEgConnectionless, TcpEgBroadcast, TcpEgConnected, TcpEg
@comment  node-name,  next,  previous,  up
@subsection Connectionless Sockets
This example can be found in the file
@file{$ICP_INSTALLDIR/examples/tcp/connectionless.pl}.

@example
/************************ connectionless server *****************************/
server :-
    tcp_connectionless(0, Socket),
    tcp_getsockaddr(Socket, Port, Address),
    writeseqnl(['server Port:', Port, '  Address:', Address]),
    writeseqnl(['Server started.',
        'You can start a client with the following command: ','\n\t',
        client(Port, Address),'.']),
    server_loop(ok, Socket).

server_loop(stop, Socket) :- !, tcp_close(Socket).
server_loop(_, Socket) :-
    tcp_recvfrom(Socket, Data, Port, Address),
    writeseqnl(['got>', Data, '<', 'from Port:', Port,
                                   '  Address:', Address]),
    server_loop(Data, Socket).

/************************ connectionless client *****************************/
client(Port, Address) :-
    tcp_connectionless(0, Socket),
    client_loop(ok, Socket, Port, Address).

client_loop(stop, Socket, _, _) :- !, tcp_close(Socket).
client_loop(end, Socket, _, _) :- !, tcp_close(Socket).
client_loop(_, Socket, Port, Address) :-
    write('enter term, "end" ends this channel, "stop" stops server> '),
    flush,
    read(Data),
    tcp_sendto(Socket, Data, Port, Address),
    client_loop(Data, Socket, Port, Address).

@end example

@node TcpEgBroadcast,  , TcpEgConnectionless, TcpEg
@comment  node-name,  next,  previous,  up
@subsection Broadcast Sockets
This example can be found in the file
@file{$ICP_INSTALLDIR/examples/tcp/broadcast.pl}.
