[DGD] While loop in auto object this_user() purpose
Raymond Jennings
shentino at gmail.com
Tue Mar 21 16:30:43 CET 2017
On Mon, Mar 20, 2017 at 2:46 PM, Gary <gary at mups.co.uk> wrote:
> auto.c has a this_user() method as follows:-
>
> static object this_user()
> {
> object user;
>
> user = ::this_user();
> while (user && user <- LIB_CONN) {
> user = user->query_user();
> }
> return user;
> }
>
> I'm curious as to why the need for the while loop.
>
> afaict in all places "user" is set in the connection object, (via the
> result of telnet_user()/binary_user() or due to a redirect() call) the
> object that query_user() would return appears to be LIB_USER derived.
>
> In which case a single user->query_user() call would be sufficient to
> obtain a user object rather than conn object.
>
> Is there a scenario that could result in user->query_user() returning a
> LIB_CONN instead in an unmodified kernel lib?
>
> If not, what was the anticipated reason a LIB_CONN might be returned by
> query_user() to necessitate a loop?
>
>
> Also, as an aside, what is the correct terminology for the auto
> this_user method? Is it a kfun or efun or neither?
>
>
> Regards,
>
> Gary
> ____________________________________________
> https://mail.dworkin.nl/mailman/listinfo/dgd
Bart answered this pretty well, so I'll give my own answer packed in a few
nutshells, both to be thorough and also for the sake of future readers of
this list.
There are two layers of abstraction involved.
DGD:
The object attached to a connection is called the user object, and it is
what directly receives calls for receive_message and open and close and so
on as documented in DGD's manual. The object is marked as a user object
when it is returned from the driver object's *_connect functions. DGD will
only close the connection if the user object associated with it is
destructed. If the connection is closed on the client's end, DGD will call
close() on the object and it will no longer be a user object.
Kernel library:
What DGD itself calls the user object, the kernel library calls the
connection object.
The kernel library keeps the user object separate from the connection
object.
Since the only way to actually close the connection is to destroy the
object DGD associated with it, this may cause problems if the same object
is used to represent the user in any way other than as a connection
endpoint. This includes keeping track of the user's account information,
the user's character's body, and so on. Furthermore, once the connection
is closed, or dies, the connection object serves no further purpose and can
be freely destructed. The kernel library does this automatically to keep
things tidy.
So the connection object maintains an internal pointer to the user object
it is associated with and forwards messages to it.
However, the kernel library is also designed so that the direct connection
object can go through a few filters of a sort before it actually reaches
the user object, thus forming a chain of objects in between that serve both
roles. This can be useful for filters or protocols such as SSH or telnet,
or if you want to enforce certain security or resource usage policies, or
if you want to wrap all user I/O inside an atomic barrier, or for any other
reason you see fit. Dworkin's SSH package does this to abstract the SSH
protocol by sending the raw I/O from the binary connection through
translation and present it as a standard text interface to the user
object. Kotaka uses such filters to enforce rlimits and optionally wrap
all I/O inside an atomic barrier, and at one point I wrote an annoying toy
that would intercept all output and put it in a buffer, and slowly return
it to the client one character at a time every fraction of a second or so.
In theory, the chain of objects between the connection object directly
associated with the network socket and the user object that actually
represents the user (who might not even be logged in or have an active
connection) can be indefinitely long with as many filters or relays in
between as is desired. The loop you found traverses that chain from the
connection object to the user object.
Since DGD itself is not aware of what the kernel library is actually
treating as a user object, its kfun this_user() refers to the object
directly associated with the connection. Iteratively following the chain
of query_conn() informs the kernel library of the actual user object.
This enforced layer of abstraction is also why the this_user() kfun is
masked in the auto object with a version that walks the chain and returns
the object at the other end of it.
Terminology:
A function defined by DGD itself is called a kfun.
A function defined in the auto object is called an afun. It is possible
for the auto object to mask a kfun by defining it as an afun.
There is no such thing as an efun in DGD. What other drivers call an efun,
DGD calls a kfun. DGD afuns are more akin to what other drivers call simul
efuns.
More information about the DGD
mailing list