Boost logo

Boost :

From: Giovanni P. Deretta (lordshoo_at_[hidden])
Date: 2005-04-23 13:42:48


Hello fellow boosters, after months of lurking on this list and seeing
how everybody seems to have its own network library, i've finally
decided to put online mine.

I will upload it under the vault as nanostream.tar.gz, it is unix/linux
only currently.

You may want to skip the library code and read the pdf under the doc
directory where the library is shortly presented and some examples are
given.

These are the main features/peculiarities of my library:

- There is no socket concept because i don't really think it is natural,
at least not for a C++ programmer. I use the acceptor, connector and
stream concepts.

- User is not required to reference streams by pointer, streams are
stack allocated or are simply members of another object. Internally they
have a smart pointer to an implementaion handle. Consider them
stack-based proxies. The acceptor and the connector return the handle
that is asigned to the stream.

- The preferred way to do input output is to use standard-like
algorithms (i.e. copy) with buffered stream adaptors and specialized
input/output iterators. I believe that an efficient library can be
written this way and be very C++-user-friendly. Classic read/write are
still available, but their semantics might be surprising.

- All classes are concrete, no polymorphism is used (i.e. no virtuals).
  Polimorphic behaviour must currently be achieved with some external
mean (i.e using the external polymorphism pattern. I think that the
boost::IDL library would be great).

- Errors can be reported both with exceptions and with error codes.
Exceptions are used by default unless error callbacks are passed. This
seems to work quite well. Internally only error codes are used and
exceptions are thrown only at the most external abstracion layer. Note
that the library does not actually use error codes, but error types
using a specialized variant object. This is just an experiment and i
might remove it. I will probably add status bits a-la iostreams.

- File streams. The library actually try to be a generalized i/o
framework, and file streams are provided for completeness.

- The library can be extended simply by creating new handles. In
addition to TCP streams there are Unix streams (come almost for free :-)
and file streams. SSL/TLS was present but did get broken some time ago
and didn't have the time to fix it.

- Input/Output buffer. This is very similar to a std::deque<char>. It
has segmented iterators support (the same interface presented in the
Austern paper), and it is the preferred input/output buffer, it can be
easilly grown on both directions (usefull if you need to add an header)
and can be efficiently read/written with scatter-gather operations.
While i have yet to implement it, i think that moving data from a buffer
to another can be done extremely efficently by splicing the internal
pages. The buffer is also used to implement the buffered adapter.
boost::arrays, vectors and plain arrays also work fine, while other
containers require a bounce buffer and thus slower operations.

- Addresses are logically defined by a triplet <domain, host, service>,
where the domain is implicit in the acceptor, address, or connector
type, host and service are two strings. This is inspired by the
getnameinfo(3) interface.

- A multithreaded stream adaptor and an http module are also included.
These are just proof of concept and not really part of the library (yet).

Missing (definitelly not complete list):

The library is fully sinchronous for now. I'm still considering how to
add asynch support. I think i will implement it in the buffered adaptor
I/O is done asynchronously to the internal buffers that can grow as much
as it is necessary.
Timeouts are definitelly a must-have.

Final notes:

I've have seen that the current consens is to encode the the stream type
  in the address, so to allow a dynamic behaviour: the actual transport
is selected only at runtime, based on the address string. I think
this is a bad decision (i considered doing it while implementing my
library) and this is why:

- C++ is a static language, let's leave these niceties to more dynamic
languages. I have found myself weeks hunting a bug in the http code
because i thought that it would be cool if i could access http
properties using a map instead of proper accessor functions. I spent
weeks hunting persistent connection bug. It was a simple typo inside a
http property string that would have been caught immediately by the
compiler if i were using functions or costants [1].

- It mimics standard library usage. You cannot open the input stream
instead of a file by using the "input:" file name. (well under Unix you
might actually do it, but i don't think this was the intention of the
standard library authors and it is not portable any way).

- It is extremely insecure. In a network library security must be
paramount. If the transport type were encoded in the address, it would
be much harder to validate externally received addresses. A similar
argument can be made for the port numbers. It is better to keep these
things separated. The library user can create its own indexed factory
collection if it really needs to.

Sorry for the long post, just tryin' to be usefull :-).

--
Giovanni P. Deretta
1 - I did write "Content-Length" instead of "Content-Lenght".

Boost list run by bdawes at acm.org, gregod at cs.rpi.edu, cpdaniel at pacbell.net, john at johnmaddock.co.uk