[prev in list] [next in list] [prev in thread] [next in thread] 

List:       kde-devel
Subject:    Socket classes in KDE3/4, updated proposal
From:       Thiago Macieira <thiagom () wanadoo ! fr>
Date:       2003-01-14 18:08:50
[Download RAW message or body]

-----BEGIN PGP SIGNED MESSAGE-----
Hash: SHA1

Ok, here it goes an updated version of the proposal.

I've taken into account Tim Jansen's suggestion of splitting into several 
specialised classes and I've also taken a look at what kind of API other 
implementations provide. 

Still missing would be a check against SCTP, to see if our proposed API would 
work with it.

Thanks for everyone who has commented. Please keep them coming.

- -- 
  Thiago Macieira - UFOT Registry number: 1001
 thiagom@mail.com
   ICQ UIN: 1967141  PGP/GPG: 0x6EF45358
     Registered Linux user #65028
-----BEGIN PGP SIGNATURE-----
Version: GnuPG v1.2.1 (GNU/Linux)

iD8DBQE+JFI5M/XwBW70U1gRArTtAJ9bOeWTAX4Ph8bNg9mcdkUv/OXjtACfVhyl
kCmCHQ26gEYvGDyVx/QYzxs=
=Ltwo
-----END PGP SIGNATURE-----

["kde4-socket-proposal.txt" (text/plain)]

Proposal for the new socket and name-resolution routines for KDE 4

Note that it might be still introduced in KDE 3 if we don't clash with
names with the existing classes. And those might be changed to use the
new structure. The new classes will be located in the KDE::Net
namespace, which means we avoid clashing with the existing
classes.

-> implementation notes and questions are marked with a preceding ->

Note for Qt
===========

This proposal can also be used to enhance Qt if some of the
functionality here proposed is instead added there instead of
KDE. This doesn't mean there won't be KDE socket classes.

Instead, it would be helpful if most of the infrastructure were
implemented inside Qt, especially the base types. The KDE classes
would, then, be wrap-arounds against those classes, implementing
needed functionality, like SOCKS support.

That is, Qt would implement all the proposed classes here, without the
KDE-specific functionality. KDE would then derive from those classes
to provide its own functionality.

Introduction
============

Name resolution
---------------

We're completely dumping Qt's name-resolution routines and address
representation. It's far from acceptable. QHostAddress doesn't allow
us to represent the data satisfactorily (for instance, Unix sockets
cannot be represented), while QDns won't honour
/etc/nsswitch.conf. (This later problem (about nsswitch.conf) is known
to TrollTech.)

Thus, we're going to use KSocketAddress and derived classes to
represent socket addresses. Those classes might be still improved upon
if they are integrated with the proposed classes for simple
addresses (no ports or other information), available in krfb. Classes
and routines for obtaining addresses from interfaces have been
proposed, as well as notification for those changes.

However, since a connection requires more information than a socket
address (namely the protocol and the socket type, since the family is
represented in a socket address), we introduce a new class to contain
that information. In the current structure, this class is the simple
KAddressInfo class. I have been thinking of changing that name to
KResolverEntry or something like that.

The proposed KResolver class should be able to handle any kind of
name-resolution task, be it synchronous or asynchronous. It might
require a background worker class or even a singleton class to handle
all requests. The idea is to allow several lower level resolution
methods while still keeping the same public API: we would then support
normal, synchronous name resolution; asynchronous name resolution;
SRV-based name resolution, etc.

* Note on asynchronous resolution: for the asynchronous resolution, it
is here proposed to use threads and make normal getaddrinfo(3)
calls. In fact, a synchronous resolution would be nothing more than an
asynchronous one run on the same thread as the caller. We should also
limit the number of concurrent resolving threads -- and if possible
allow a program to change those values.

Sockets
-------

For the socket part, Qt already has a lot of useful functionality in
the low-level QSocketDevice and in the buffering done by
QSocket. However, these classes lack some functionality we want added
and they use the name-resolution API we want to dump.

One idea is to create derived classes from them and override the
functions not wanted. Another is to completely dump those classes and
work on our own framework. 

From my point of view, the ideal thing would be to have a generic
abstract base class, one low-level (much like QSocketDevice) class
built on top of it and specialised classes that work on different
kinds of sockets.

For the specialised socket classes, the following specialisations (and
sub-specialisations) have been proposed:
   @ client (active) socket
     * streaming socket
       - buffered streaming socket
     * datagram socket
       - multicast datagram socket
   @ server (passive) socket

Thus the class tree would be:
  QIODevice [abstract]
   \- KAsyncIO [abstract]
      \- KBaseSocket [abstract]
           +- KSocketDevice
	   +- KClientSocket [abstract]
  	   |    +- KStreamSocket
	   |    |    \- KBufferedSocket
	   |    \- KDatagramSocket
	   |         \- KMulticastSocket
	   \- KServerSocket

The abstract base class would contain methods common to all
implementations (low-level and high-level alike), as well as pure
virtual methods for what must be implemented in derived classes --
reading, writing, etc. (note: those are already inherited from
QIODevice).

KAsyncIO is in the diagram above, but its functionality should instead
be in QIODevice: signals notifying of the possibility of reading and
writing. Note for server sockets: an extra signal called readyAccept()
should be added.

Class description
=================

KResolver: public QObject
	Resolves host/service combinations into binary (address, port,
	scope, etc.) forms. Can do it synchronous or asynchronously. This
	should completely replace KExtendedSocket's name resolution
	functions, both the ones used in objects and the static ones.

	* constructor and setAddress/setHost/setService functions much
          like the current KExtendedSocket
	* setFlags for getaddrinfo-like flags (AI_*)
	  but don't use the system constants!
	* startSync and startAsync
	* signal resultsReady()
	* KResolverResults results()

	-> should we implement the socket type restrictions here,
           during resolution? I.e., tell the resolver if we want only
           Internet sockets, or Unix sockets as well, etc.?

KResolverResults: public QList<> or QArray<>
	Keeps an array or list of results from a name
	resolution. Should be one of the QList, QArray, so that we can
	use iterators and etc. Currently, this is represented by a
	QValueList<KAddressInfo>, as returned by the static member
	function KExtendedSocket::lookup.

KResolverEntry or KAddressInfo
	The internal type carried by KResolverResults. Like the
	current KAddressInfo, one has to be able to access the
	internal data in KSocketAddress form.

	-> make them more easily copiable
	-> they don't derive from QObject
	-> deep copy

KBaseSocket: public KAsyncIO [abstract]
	This is the base, abstract class from which all socket types
	will be derived. This class defines the socket functionality
	that should be present in any socket and that are not already
	inherited from QIODevice.

	Here follows a list of proposed methods for the class, but I
	wouldn't say the list is exhaustive. Only when writing the
	classes themselves will anyone know what is common to all of
	them, and can thus be bumped up in the hierarchy. The same is
	true for the methods in KClientSocket.

	* create(void): create the socket, but do nothing on it.
	  This could be later hidden in derived classes
	  -> pure virtual?
	  -> should we have this method?
	* setSocketFamilies: set the allowed socket families, like
	  Unix or Internet (IPv4 and v6).
	* socketDevice/setSocketDevice: sets the socket device, of
	  type KSocketDevice*
	* state and error management:
	  we'd use QIODevice's IO_* constants to describe what kind of
	  error happened (read, write, accept, listen, connect, etc.),
	  and a set of error codes describing what exactly the
	  error. This second set should be source-compatible with
  	  QSocket's and wrap around getaddrinfo()'s EAI_* error codes.
	  errno should be recorded too.
	* m_fd: file descriptor protected member
	* setBlockingMode, setAddressReusable
	* QSocketNotifiers

KSocketDevice: public KBaseSocket
	Simple socket that doesn't do name resolution or buffering or
	anything (like QSocketDevice). While this is not derived from
	QSocketDevice, which would be desireable if multiple
	inheritance were permitted, we can "fake" that condition by
	providing cast operators to QSocketDevice*, and sending an
	internal derived class in that place.

	That class will also be the one actually doing the I/O
	operations, using Qt's already established implementation.

	We'd accomplish the "fake" inheritance by having:
	class ourOwnQSocketDevice: public QSocketDevice
	  {
	    operator KSocketDevice* ();
	  }
	and in KSocketDevice:
	  operator ourOwnQSocketDevice* ();
	This class (whose name should be something else, of course),
	would be the real brains behind the scenes, doing almost if
	not all the work. KSocketDevice would only redirect to it.

	If TrollTech adds this functionality to Qt, however, the point
	is moot: QSocketDevice will be the class we want.

	It will do only the low-level socket operations:
	* create (of a family, type and protocol)
	* bind(KSocketAddress/KResolverResult)
	* connect(KSocketAddress/KResolverResult)
	* listen(int backlog)
	* accept(KSocketDevice*&)
	* read, recv, recvfrom
	* write, send, sendto
	* retrieve addresses (local & peer)
	* select/poll

	-> bind, connect will override QSocketDevice's ugly
	  QHostAddress functions. We shall provide KSocketAddress and
	  KResolverResult variants.
	-> verify which QSocketDevice functions require overriding:
	  listen
	  accept
	  (set)addressReusable
	  bytesAvailable
	  waitForMore

KClientSocket: public KBaseSocket [abstract]
	Most of the socket functionality that wraps around the socket
	device and the resolution routines. No buffering or anything
	else is done. The idea is to wrap around KSocketDevice and
	name-resolution and add a bit of functionality for client
	sockets (i.e., reading and writing), that is common to all
	kinds of sockets, datagram and streaming alike.

	Even though no buffering is to be done, asynchronous
	name-lookup and connection are to be available.

	* setRemoteAddress(QString host, QString service) and
  	  KExtendedSocket-like variants
	* setRemoteAddress(KResolverResult/KSocketAddress)	
	* setLocalAddress(QString host, QString service) and variants
	* setLocalAddress(KResolverResult/KSocketAddress)	
	* read, recv, recvfrom
	* peek
	* write, send, sendto
	* other QSocket- and KExtendedSocket-like operations, like
  	  bytesAvailable, etc.
	* canRead, canWrite
	* signal hostFound(), error(int)
	* signal readyRead(), readyWrite(), connectionClosed()
	* public members bytesSent, bytesReceived

	-> KServerSockets also have setLocalAddress. Should that be
           moved up in the hierarchy to KBaseSocket?
	-> bytesWritten/bytesReceived is proposed public so that the
           user may, if he wants, reset it to any value. Who knows
           what kind of accounting he will want?
	-> the I/O operations here are just calls wrapping around the
           internal KSocketDevice object

KStreamSocket: public KClientSocket
	This is an unbuffered streaming socket. That is, it implements
	SOCK_STREAM kind of sockets, which are the most commonly used
	ones. The difference from QSocket is that this class does not
	do buffering.

	* open, create, connect

	-> recvfrom, sendto are probably to be hidden. A connected
           socket cannot send to or receive from other addresses than
           that to which it is connected.

KBufferedSocket: public KStreamSocket
	This should be a fully-buffered socket and work very much like
	KSocket, but better ;-) We'd inherit all the KStreamSocket
	functionality and also provide buffering.

	Also to be noted: for changing a socket from buffered to
	non-buffered, one would create a new class and set the socket
	device.

	Also note that this class should be source-compatible with
	QSocket, except for what we want to dump (QHostAddress and
	IPv4-isms).

	* signal bytesWritten(int count)
	* signal delayedCloseFinished()
	* override close and provide closeNow()

	-> modify KBufferedIO so that it can be used to buffer (i.e.,
           make it a KBuffer class -- we'd use one for input and the
           other for the output buffer)

KDatagramSocket: public KClientSocket
	This is a datagram socket. That is, it's a normal client
	socket, but of SOCK_DGRAM type. It should also implement
	connectionless functionality.

	* open, create
	* connect/disconnect
	  Note: you can connect more than once when using a datagram
	  socket and you can also disconnect by connecting to a
	  certain address.

KMulticastSocket: public KDatagramSocket
        This is also a datagram socket, but it's by definition
        connectionless (so we can hide the connect routines), and we
        should implement some multicast functionality:

	* joining, leaving groups
	* setting scope (TTL in IPv4)

	Note that multicast sockets are tricky. For one thing,
	multicast isn't even mandatory in IPv4. And in IPv6, it's
	already very different. This KMulticastSocket class should be
	regarded as a low-priority one and left to be implemented only
	if we are certain of what we're doing.

	If the IPv4 and v6 differences are too great, splitting this
	class in two might be needed. I have no idea how multicasting
	works on non-Internet protocols.

KServerSocket: public KBaseSocket
	This is a passive socket, which will listen and accept socket
	connections. We should be able to set some socket
	identifications, like datagrams or even buffering. That way,
	one could use this class to get also several kinds of
	specialised sockets.

	QServerSocket works on the assumption that one will derive
	from the class and implement one function to handle it. That
	is not always desired, and for that it is proposed that
	KServerSocket not be source-compatible with QServerSocket.

	* setLocalAddress(QString host, QString service)
	* setLocalAddress(KResolverResult/KSocketAddress)
	* listen(int backlog)
	* accept(KClientSocket*&): returns a KStreamSocket or a
	  KDatagramSocket depending on whether we've been set to
	  stream or datagram. Multicast sockets can't accept.
	* signal readyAccept()

>> Visit http://mail.kde.org/mailman/listinfo/kde-devel#unsub to unsubscribe <<

[prev in list] [next in list] [prev in thread] [next in thread] 

Configure | About | News | Add a list | Sponsored by KoreLogic