
Hi, Pedro Lamarão wrote:
How do you interpret the results of name resolution and pass that to the "connect" and "bind" equivalents? Do the "client" and "listener" classes automatically call the resolver?
Yes, that is the plan (name resolution is not implemented yet). A socket stream can be constructed with an optional reference to a "manager" class (which is the select() wrapper, basically), which holds a set of resolvers (similar to locale facets). If a manager object is given, it is asked for a resolver, which is given the query and a method to call on completion, then control is transferred back to the caller. If no manager object is given, a resolver is instantiated, the name resolved and the resolver destroyed (=> you need a manager for nonblocking I/O). The resolver is usually called by the manager when the application enters its idle loop, so applications may not wait for connections to get established when they use a manager object.
But the need for the existence of a "socket" class is questionable; the IO primitive in the C++ standard library is the streambuf; ugly or not, it provides a complete "client" for a networking library.
My streambufs hold a pointer to an abstract "impl" class which represents the actual socket. Concrete subclasses of that exist for different socket types, so new address families can be added at runtime (currently, only through my plugin interface, which I wrote about to the list a few days ago).
That auto_ptr is there because stream objects are not copyable, and the purpose of that "listener" is to internalize the "accept" primitive and the stream constructor.
They are not copy-constructible, that is different from not copiable :-). A new streambuf can be attached to an existing stream, as long as care is taken to properly destroy the streambuf on stream close).
I'd be happier to return an "rvalue reference" there, if we already had such a thing.
Hrm, they could be made copy-constructible, I think, the benefit of that would however be questionable.
In the example/ directory of the socketstream project, check out the asynch_resolver.h file; there's an asynchronous version of the resolver class there implemented using boost::thread.
I avoid spawning new threads from library functions like the plague, as it is difficult to properly collect those threads in case of an exception etc.
I suspect there's little hope of doing anything different than keeping a std::vector or std::list of whatever networking object we're holding, and creating the proper structure for select() or poll() when calling the blocker method. That might make the blocker method O(n) on the number of networking objects...
I think the manager object should have a list of pointers to the streams it monitors and have a callback registered with them so the stream is scheduled for removal on stream destruction (we cannot unregister the stream right away as there might be iterators in the list of pointers that we'd invalidate). I think we should attempt to coordinate our efforts here. Simon