
Hi Boris, I hope all is going well.
That said I am trying to find out what your library offers to understand if it belongs to the same package which is called "ace" right now. Or your library has different goals which means we need another package in level 1 or even worse a new level. In the end the network library can and should consist of different packages to meet different requirements but it should be very clear to library users which requirements are met by each package.
I agree on the goals for each package. The library I am proposing is logically the same as sockets, but of course, it must be implemented somehow (sockets typically). Ideally, there would be nothing between it and the most primitive/best-performing library available. Various implementations of the interfaces would map to whatever mechanism was available (see below).
As far as I understand the acceptor-connector pattern the idea is that a connector behaves like an acceptor. This means both of them are factories producing connected streams. Most network developers (who know Berkeley sockets) will probably create an acceptor based on accept() and a connector based on connect(). The acceptor will work as a factory but the connector can probably be used only once to create one connected stream.
The reason I suppose that I preferred not-yet-connected as a state of stream (vs. a separate class) is that it is logically a 1-to-1 relationship (and even the same socket) whereas acceptor is a 1-to-N relationship (the acceptor socket never becomes something else). The other reason I went with the approach I have is that there is only one object to deal with for cancel. I don't need to worry about the transition from connecting to connected when I want to abort.
This is what I did in http://www.highscore.de/boost/net/basic.png and comes close to the C API. If we think of unexperienced developers who don't know any sockets they will probably be happy if the connector behaves like the acceptor as they wouldn't understand the difference.
I would find this more difficult. With an acceptor, I am doing one thing (accepting connections), but with _each_ stream connection, I am doing one thing. In this respect, the socket approach feels right: an acceptor is a thing, and a not-yet-connected stream is also its own thing (which may become connected eventually).
Regarding the acceptor and connector your library seems to be close what I made up in the class hierarchy and therefore would belong to level 0.
I think that is consistent in that it is an attempt to hide sockets which is at level 0 (maybe they will move down to -1<g>).
My goal is to iron out a behavior contract that satisfies various possible and desired implementations, so that a library user can know what are safe and portable practices. One could say that the sockets API does this, but there are two central issues: one cannot create a new type of socket (to layer protocols); not all forms of I/O completion are portable.
I am surprised to read this! The socket API - the so-called level 0 - must and will be portable. It should be possible to derive classes from socket and create new types. And all four types of I/O must be supported in level 0, too. What kind of problems do you see here?
Some platforms have socket features that aren't available on other platforms. Unix has signal-driven I/O, while Windows does not. Windows has event object based I/O, completion ports, HWND messages, etc. which are unique to it. The common intersection is blocking, non-blocking and select. One can write 99% portable sockets code based on that subset. Except that Windows has restrictions on select(). A single fd_set must be <= 64 sockets. You cannot mix sockets from different providers (which I understand to mean IPv4 vs. v6 vs. IPX vs. whatever). Also, select() is for sockets only, not files, not pipes, not fill_in_the_blank. One cannot make a sockets layer that hides these issues without violating the spirit of this layer: thin. Hence, my proposal. I believe the right answer is to write an ideal network interface. One that focuses on behaviors and not the API's used to implement them. On some platforms, this implementation can be fairly thin. Of course, it can also provide a robust thread-pooling implementation and probably has to on Windows (because of the 64 socket limit). On Linux, it could use epoll. All are wonderful areas to explore. Which brings me to notification via callback. Whenever user code is called by a library, there must be clear rules and expectations. One good way to make things difficult would be to make callbacks to user code from a signal handler. Of course, threads can also present a similar problem. It is all well and good to provide choices to the application author, but we cannot forget the vital role of protocol library authors. So, what I think is necessary is a description of rules and things one can expect when using async calls specifically. Without clear and unequivocal rules, protocol library authors would have to constantly wonder about these important details. So, let's pick on an SSL stream implementation based on OpenSSL. IMHO, the ideal implementation of such a thing would consume an abstract stream (so it could be used over any arbitrary transport) and provide the same stream features. Since this is a user library, the OpenSSL stream is not a socket. It cannot create some entity that can be passed to the socket API. This is what I meant by "we cannot create new kinds of sockets". Further, because the SSL stream makes I/O requests, it must understand what is supported and how async callbacks work. It must present exactly those same behaviors to its user.
If the network library should support platform-specific features we should indeed add another package to http://www.highscore.de/boost/net/packages.png. This package would be optional. However it would be nice if classes from this package would collaborate somehow with classes from the other non-optional packages of the network library. The non-optional packages would provide a default implementation and library users could use optimized classes from the optional package depending on the platform they are using.
I agree (I think<g>). There will always be non-portable concerns and one can always address them by writing directly to the API for the platform. Once a library is interposed, things change. What I was expecting in this area was that the lowest-level API wrappers (mostly sockets) are entities that can be used in platform-specific ways because they provide their native descriptor to the user. But, this is a "chose your layer and portability goals" question for the app. To exercise such features, one will have to go around the interfaces I am proposing. Best, Don __________________________________________________ Do You Yahoo!? Tired of spam? Yahoo! Mail has the best spam protection around http://mail.yahoo.com