[Top][All Lists]

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

Re: New patch for server sockets and datagram (UDP) support.

From: Kim F. Storm
Subject: Re: New patch for server sockets and datagram (UDP) support.
Date: 08 Mar 2002 00:58:49 +0100
User-agent: Gnus/5.09 (Gnus v5.9.0) Emacs/21.2.50

Helmut Eller <address@hidden> writes:

> > > It's probably a pain to parse keyword arguments in C, but it frees you
> > > from overloading positional arguments in an unnatural way.  It would
> > > also be quite nice to use from Lisp.  Another advantage is that you
> > > could add new arguments without much backward compatibility
> > > restrictions.

Below is the doc-string for make-network-process which is a keyword
based replacement for the built-in open-network-stream.  I already
implemented most of the code handling this, and it looks quite clean
compared to the previous version.

IMO, this it by far the best proposal for the API so far.

The lisp-level wrappers will look like this:

(defun open-network-stream (name buffer host service)
  (make-network-process :name name :buffer buffer
                        :host host :service service))

(defun open-network-stream-nowait (name buffer host service &optional sentinel 
  (if (make-network-process :feature :nowait t)
      (make-network-process :name name :buffer buffer :nowait t
                            :host host :service service
                            :filter filter :sentinel sentinel)))

(defun open-stream-server (name buffer service &optional host sentinel filter)
  (make-network-process :name name :buffer buffer :server t
                        :host host :service service))

DEFUN ("make-network-process", Fmake_network_process, Smake_network_process, 
       0, MANY, 0, 
       doc: /* Create and return a network server or client process.
Input and output work as for subprocesses; `delete-process' closes it.

Arguments are specified as keyword/argument pairs.  The following
arguments are defined:

:name NAME -- NAME is name for process.  It is modified if necessary
to make it unique.

:buffer BUFFER -- BUFFER is the buffer (or buffer-name) to associate
with the process.  Process output goes at end of that buffer, unless
you specify an output stream or filter function to handle the output.
BUFFER may be also nil, meaning that this process is not associated
with any buffer.

:host HOST -- HOST is name of the host to connect to, or its IP
address.  If specified for a server process, only clients on that host
may connect.  The symbol `local' specifies the local host.

:service SERVICE -- SERVICE is name of the service desired, or an
integer specifying a port number to connect to.  If port number is 0,
a random port number is selected for the

:family FAMILY -- FAMILY is the address (and protocol) family for the
service specified by HOST and SERVICE.  The default address family is
Inet (or IPv4) for the host and port number specified by HOST and
SERVICE.  Other address families supported are:
  local -- for a local (i.e. UNIX) address specified by SERVICE.

:datagram BOOL -- Create a datagram type connection if BOOL is
non-nil.  Default is a stream type connection.

:nowait BOOL -- Don't wait for client process to complete the
connection to the server if BOOL is non-nil; instead, the sentinel
function will be called with second matching "open" (if successful) or
"failed" when the connect completes.  Default is to use a blocking

:filter FILTER -- Install FILTER as the process filter.

:sentinel SENTINEL -- Install SENTINEL as the process sentinel.

:server BOOL -- if BOOL is non-nil, create a server process for the
specified FAMILY, SERVICE, and connection type (stream or datagram).
Default is a client process.

A server process will listen for and accept connections from
clients.  When a client connection is accepted, a new network process
is created for the connection with the following parameters: 
- The client's process name is constructed by concatenating the server
process' NAME and a client identification string.
- If the FILTER argument is non-nil, the client process will not get a
separate process buffer; otherwise, the client's process buffer is a newly
created buffer named after the server process' BUFFER name or process
NAME concatenated with the client identification string.  
- The connection type and the process filter and sentinel parameters are
inherited from the server process' TYPE, FILTER and SENTINEL.
- The client process' contact info is set according to the client's
addressing information (typically an IP address and a port number).

Notice that the FILTER and SENTINEL args are never used directly by
the server process.  Also, the BUFFER argument is not used directly by
the server process, but via `network-server-log-function' hook, a log
of the accepted (and failed) connections may be recorded in the server
process' buffer.

The following special call returns t iff a given KEY VALUE
pair is supported on this system:
  (make-network-process :feature KEY VALUE)  */)
     (nargs, args)
     int nargs;
     Lisp_Object *args;

> > >  I propose
> > > to make gethostbyname and related functions available to Lisp.  IP
> > > addresses could be represented by vectors of 4 bytes (it's a pity that
> > > 32bit don't fit into a ELisp fixnum).
> > >
> > 
> > Not that I object to this in general, but for what purpose? 
> Because there is currently no way to get the IP address(es) of the
> current host.  It MAY also simplify the C level implementation,
> because you could require that e.g. the SERVICE argument is actually a
> port number and not a string or a number; similar for the HOST
> argument.
I don't think this is necessary, so I'll leave that for a future
enhancement.  To restrict connections to the local host, I suggest 
using either "localhost" for the HOST or as local (UNIX) socket.

> > > Yet another point: please, please, please make accept-connection a
> > > separate function.  Then one could make a _blocking_ accept; also
> > > accept with a timeout argument would be possible.
> > 
> > I understand that you want to serialize the connections.
> > Why is it necessary to do that?  
> It's probably not necessary in 95% of all uses, but it may be hard to
> change later if you hardwire the current behavior.  And, about every
> socket interface I have seen so far has a separate accept function.
> Here is a somewhat artificial example.  I would like to control Emacs
> from an external Common Lisp program.  I would also like to control
> the Common Lisp program from Emacs.  Do to this I implemented a very
> naive rpc mechanism: both sides send their commands via a socket
> connection to the peer, the peer evals the command and sends the
> result back to the client.  Now the problem: if the command include a
> recursive/nested calls to caller, serialization is an issue.  The
> cleanest thing is to accept exactly one connection at a time.  Of
> course, it is not very hard to come up with different solution, but
> accept-connection makes this particular use elegant and reliable.
Ok, but as you mention yourself, this is the exception, so it
shouldn't be the standard behaviour.  I will take a look at using
stop-process and start-process to temporarily inhibit a server socket
from accepting connections.  If you can use stop-process in
the sentinel, this seems to be a cleaner solution than 
having to (re-)enable the server by calling accept-connection.

Kim F. Storm <address@hidden> http://www.cua.dk

reply via email to

[Prev in Thread] Current Thread [Next in Thread]