summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorschmidt <douglascraigschmidt@users.noreply.github.com>1998-08-26 01:44:12 +0000
committerschmidt <douglascraigschmidt@users.noreply.github.com>1998-08-26 01:44:12 +0000
commiteea0021983aea847af979abcd1fd0b0376d89af4 (patch)
tree7ec316aa14543dffaf1b713f9f851b9ab138b60c
parentc2d44f8500ad2064fafe2188e3aefde62bc15652 (diff)
downloadATCD-eea0021983aea847af979abcd1fd0b0376d89af4.tar.gz
*** empty log message ***
-rw-r--r--docs/tutorials/001/00SetEnv2
-rw-r--r--docs/tutorials/001/Makefile46
-rw-r--r--docs/tutorials/001/Source.tgzbin0 -> 1776 bytes
-rw-r--r--docs/tutorials/001/acceptor.h64
-rw-r--r--docs/tutorials/001/logger.h75
-rw-r--r--docs/tutorials/001/page01.html107
-rw-r--r--docs/tutorials/001/page02.html121
-rw-r--r--docs/tutorials/001/page03.html285
-rw-r--r--docs/tutorials/001/page04.html239
-rw-r--r--docs/tutorials/001/page05.html53
-rw-r--r--docs/tutorials/001/server.cpp34
-rw-r--r--docs/tutorials/002/00SetEnv2
-rw-r--r--docs/tutorials/002/Makefile42
-rw-r--r--docs/tutorials/002/acceptor6
-rw-r--r--docs/tutorials/002/handler81
-rw-r--r--docs/tutorials/002/main36
-rw-r--r--docs/tutorials/002/page01.html57
-rw-r--r--docs/tutorials/002/page02.html174
-rw-r--r--docs/tutorials/002/page03.html65
-rw-r--r--docs/tutorials/002/page04.html265
-rw-r--r--docs/tutorials/002/page05.html41
-rw-r--r--docs/tutorials/002/serverbin0 -> 174553 bytes
-rw-r--r--docs/tutorials/002/server.cpp124
-rw-r--r--docs/tutorials/003/00SetEnv2
-rw-r--r--docs/tutorials/003/Makefile66
-rw-r--r--docs/tutorials/003/clientbin0 -> 36378 bytes
-rw-r--r--docs/tutorials/003/client.cpp38
-rw-r--r--docs/tutorials/003/page01.html168
-rw-r--r--docs/tutorials/004/00SetEnv2
-rw-r--r--docs/tutorials/004/Makefile68
-rw-r--r--docs/tutorials/004/clientbin0 -> 45871 bytes
-rw-r--r--docs/tutorials/004/client.cpp141
-rw-r--r--docs/tutorials/004/foo141
-rw-r--r--docs/tutorials/004/page01.html184
-rw-r--r--docs/tutorials/005/00SetEnv2
-rw-r--r--docs/tutorials/005/Makefile42
-rw-r--r--docs/tutorials/005/acceptor6
-rw-r--r--docs/tutorials/005/handler81
-rw-r--r--docs/tutorials/005/main36
-rw-r--r--docs/tutorials/005/page01.html59
-rw-r--r--docs/tutorials/005/page02.html178
-rw-r--r--docs/tutorials/005/page03.html67
-rw-r--r--docs/tutorials/005/page04.html126
-rw-r--r--docs/tutorials/005/page05.html352
-rw-r--r--docs/tutorials/005/page06.html42
-rw-r--r--docs/tutorials/005/page07.html333
-rw-r--r--docs/tutorials/005/serverbin0 -> 166555 bytes
-rw-r--r--docs/tutorials/005/server.brk154
-rw-r--r--docs/tutorials/005/server.cpp149
-rw-r--r--docs/tutorials/005a/00SetEnv2
-rw-r--r--docs/tutorials/005a/DEADJOE158
-rw-r--r--docs/tutorials/005a/Makefile42
-rw-r--r--docs/tutorials/005a/Makefile4broken42
-rw-r--r--docs/tutorials/005a/acceptor6
-rw-r--r--docs/tutorials/005a/handler81
-rw-r--r--docs/tutorials/005a/main36
-rw-r--r--docs/tutorials/005a/main.cpp34
-rw-r--r--docs/tutorials/005a/page01.html59
-rw-r--r--docs/tutorials/005a/page02.html178
-rw-r--r--docs/tutorials/005a/page03.html65
-rw-r--r--docs/tutorials/005a/page04.html274
-rw-r--r--docs/tutorials/005a/page04a.html97
-rw-r--r--docs/tutorials/005a/page05.html97
-rw-r--r--docs/tutorials/005a/page06.html42
-rw-r--r--docs/tutorials/005a/serverbin0 -> 159201 bytes
-rw-r--r--docs/tutorials/005a/server.bck160
-rw-r--r--docs/tutorials/005a/server.cpp145
-rw-r--r--docs/tutorials/005a/server.dyn144
-rw-r--r--docs/tutorials/005a/server.news139
-rw-r--r--docs/tutorials/005a/serverBrokenbin0 -> 159171 bytes
-rw-r--r--docs/tutorials/005a/serverBroken.cpp143
-rw-r--r--docs/tutorials/006/Makefile42
-rw-r--r--docs/tutorials/006/ideas01100
-rw-r--r--docs/tutorials/006/index.html104
-rw-r--r--docs/tutorials/006/notifybin0 -> 103762 bytes
-rw-r--r--docs/tutorials/006/notify.cpp199
-rw-r--r--docs/tutorials/006/page01.html234
-rw-r--r--docs/tutorials/006/page02.html6
-rw-r--r--docs/tutorials/006/serverbin0 -> 191435 bytes
-rw-r--r--docs/tutorials/006/server.cpp388
-rw-r--r--docs/tutorials/index.html98
-rwxr-xr-xdocs/tutorials/linify52
-rw-r--r--docs/tutorials/page03.html285
-rw-r--r--etc/ACE-tutorials-intro.html72
-rw-r--r--etc/ACE-tutorials-overview.html50
85 files changed, 7930 insertions, 0 deletions
diff --git a/docs/tutorials/001/00SetEnv b/docs/tutorials/001/00SetEnv
new file mode 100644
index 00000000000..eca78e10c85
--- /dev/null
+++ b/docs/tutorials/001/00SetEnv
@@ -0,0 +1,2 @@
+export ACE_ROOT=/local/src/ACE/ACE_wrappers
+export LD_LIBRARY_PATH=$ACE_ROOT/ace:$LD_LIBRARY_PATH
diff --git a/docs/tutorials/001/Makefile b/docs/tutorials/001/Makefile
new file mode 100644
index 00000000000..6bd430974cf
--- /dev/null
+++ b/docs/tutorials/001/Makefile
@@ -0,0 +1,46 @@
+#----------------------------------------------------------------------------
+# $Id$
+#
+# Makefile for the Reactor Server Logging Daemon
+#----------------------------------------------------------------------------
+
+#----------------------------------------------------------------------------
+# Local macros
+#----------------------------------------------------------------------------
+
+BIN = server
+
+FILES =
+
+LSRC = $(addsuffix .cpp,$(FILES))
+LOBJ = $(addsuffix .o,$(FILES))
+SHOBJ = $(addsuffix .so,$(FILES))
+
+LDLIBS = $(addprefix .shobj/,$(SHOBJ))
+
+VLDLIBS = $(LDLIBS:%=%$(VAR))
+
+BUILD = $(VBIN)
+
+#----------------------------------------------------------------------------
+# Include macros and targets
+#----------------------------------------------------------------------------
+
+include $(WRAPPER_ROOT)/include/makeinclude/wrapper_macros.GNU
+include $(WRAPPER_ROOT)/include/makeinclude/macros.GNU
+include $(WRAPPER_ROOT)/include/makeinclude/rules.common.GNU
+include $(WRAPPER_ROOT)/include/makeinclude/rules.nonested.GNU
+include $(WRAPPER_ROOT)/include/makeinclude/rules.lib.GNU
+include $(WRAPPER_ROOT)/include/makeinclude/rules.bin.GNU
+include $(WRAPPER_ROOT)/include/makeinclude/rules.local.GNU
+
+#----------------------------------------------------------------------------
+# Local targets
+#----------------------------------------------------------------------------
+
+#----------------------------------------------------------------------------
+# Dependencies
+#----------------------------------------------------------------------------
+
+.obj/server.o .shobj/server.so: server.cpp acceptor.h logger.h
+
diff --git a/docs/tutorials/001/Source.tgz b/docs/tutorials/001/Source.tgz
new file mode 100644
index 00000000000..9789c46e1e2
--- /dev/null
+++ b/docs/tutorials/001/Source.tgz
Binary files differ
diff --git a/docs/tutorials/001/acceptor.h b/docs/tutorials/001/acceptor.h
new file mode 100644
index 00000000000..443750f88a7
--- /dev/null
+++ b/docs/tutorials/001/acceptor.h
@@ -0,0 +1,64 @@
+/* -*- C++ -*- */
+// $Id$
+
+#if !defined (_LOGGING_ACCEPTOR_H)
+#define _LOGGING_ACCEPTOR_H
+
+#include "ace/SOCK_Acceptor.h"
+#include "ace/Event_Handler.h"
+
+#include "logger.h"
+
+class Logging_Acceptor : public ACE_Event_Handler
+{
+ friend class Logging_Handler;
+public:
+
+ Logging_Acceptor ( const ACE_INET_Addr &addr) : peer_acceptor_(addr)
+ {
+ }
+
+ ~Logging_Acceptor (void)
+ {
+ this->handle_close (ACE_INVALID_HANDLE, ACE_Event_Handler::READ_MASK);
+ }
+
+
+ virtual int open (const ACE_INET_Addr &addr)
+ {
+ if (this->peer_acceptor_.open (addr, 1) == -1)
+ return -1;
+ else
+ return 0;
+ }
+
+private:
+
+ virtual ACE_HANDLE get_handle (void) const
+ {
+ return this->peer_acceptor_.get_handle ();
+ }
+
+ virtual int handle_input (ACE_HANDLE)
+ {
+ Logging_Handler *svc_handler = new Logging_Handler;
+
+ if (this->peer_acceptor_.accept (*svc_handler) == -1)
+ ACE_ERROR_RETURN ((LM_ERROR, "%p", "accept failed"), -1);
+ else if (svc_handler->open () == -1)
+ svc_handler->close ();
+
+ return 0;
+ }
+
+ virtual int handle_close (ACE_HANDLE, ACE_Reactor_Mask)
+ {
+ return this->peer_acceptor_.close ();
+ }
+
+
+ ACE_SOCK_Acceptor peer_acceptor_;
+};
+
+#endif /* _LOGGING_ACCEPTOR_H */
+
diff --git a/docs/tutorials/001/logger.h b/docs/tutorials/001/logger.h
new file mode 100644
index 00000000000..0a4a4d12ba3
--- /dev/null
+++ b/docs/tutorials/001/logger.h
@@ -0,0 +1,75 @@
+// $Id$
+
+#if !defined (_LOGGING_HANDLER_H)
+#define _LOGGING_HANDLER_H
+
+#include "ace/Event_Handler.h"
+#include "ace/INET_Addr.h"
+#include "ace/SOCK_Stream.h"
+
+class Logging_Handler : public ACE_Event_Handler
+{
+public:
+ Logging_Handler (void)
+ {
+ }
+
+ virtual int open (void)
+ {
+ if (g_reactor-> register_handler (this, ACE_Event_Handler::READ_MASK) == -1)
+ ACE_ERROR_RETURN ((LM_ERROR, "(%P|%t) can't register with reactor\n"), -1);
+ }
+
+ virtual int close (void)
+ {
+ return this->handle_close (ACE_INVALID_HANDLE, ACE_Event_Handler::RWE_MASK);
+ }
+
+ operator ACE_SOCK_Stream &()
+ {
+ return this->cli_stream_;
+ }
+
+protected:
+ virtual ACE_HANDLE get_handle (void) const
+ {
+ return this->cli_stream_.get_handle ();
+ }
+
+ virtual int handle_input (ACE_HANDLE)
+ {
+ char buf[128];
+ memset(buf,0,sizeof(buf));
+
+ switch( this->cli_stream_.recv(buf,sizeof buf) )
+ {
+ case -1:
+ ACE_ERROR_RETURN ((LM_ERROR, "(%P|%t) %p bad read\n", "client logger"), -1);
+ case 0:
+ ACE_ERROR_RETURN ((LM_ERROR, "(%P|%t) closing log daemon (fd = %d)\n",
+ this->get_handle ()), -1);
+ default:
+ ACE_DEBUG ((LM_DEBUG, "(%P|%t) from client: %s",buf));
+ }
+
+ return 0;
+ }
+
+ virtual int handle_close (ACE_HANDLE, ACE_Reactor_Mask)
+ {
+ delete this;
+ return 0;
+ }
+
+ virtual ~Logging_Handler (void)
+ {
+ g_reactor-> cancel_timer (this);
+ this->cli_stream_.close ();
+ }
+
+private:
+ ACE_SOCK_Stream cli_stream_;
+};
+
+#endif /* _LOGGING_HANDLER_H */
+
diff --git a/docs/tutorials/001/page01.html b/docs/tutorials/001/page01.html
new file mode 100644
index 00000000000..d76a6c32dd0
--- /dev/null
+++ b/docs/tutorials/001/page01.html
@@ -0,0 +1,107 @@
+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 3.2//EN">
+<HTML>
+<HEAD>
+ <TITLE>ACE Tutorial 001</TITLE>
+ <META NAME="GENERATOR" CONTENT="Mozilla/3.01Gold (Win95; I) [Netscape]">
+ <META NAME="Author" CONTENT="James CE Johnson">
+ <META NAME="Description" CONTENT="A first step towards using ACE productively">
+</HEAD>
+<BODY text = "#000000" link="#000fff" vlink="#ff0f0f" bgcolor="#ffffff">
+
+
+<CENTER><P><B><FONT SIZE=+2>ACE&nbsp;Tutorial 001<BR>
+A Beginners Guide to Using the ACE&nbsp;Toolkit</FONT></B></P></CENTER>
+
+<P>
+<HR WIDTH="100%"></P>
+
+<P>The purpose of this tutorial is to show you how to create a very simple
+server capable of handling multiple client connections. Unlike a &quot;traditional&quot;
+server application, this one handles all requests in one process. Issues
+of multi-processing and multi-threading will be handled in later tutorial.</P>
+
+<P>
+<HR WIDTH="100%"></P>
+
+<P>What do you need to create a server?</P>
+
+<OL>
+<LI>Something which accepts connections from clients</LI>
+
+<LI>Something which handles established connections</LI>
+
+<LI>A main program loop that handles it all</LI>
+</OL>
+
+<P>The ACE&nbsp;Acceptor provides a solution for our first requirement.
+This class is given a TCP/IP&nbsp;port number on which it will listen for
+incoming connections. When a connection is attempted, the acceptor will
+create a new object (the handler) to deal with the client connection while
+the acceptor goes back to listening for other connections.</P>
+
+<P>The ACE&nbsp;EventHandler solves our second requirement. This doesn't
+seem obvious now but as we progress through this tutorial it will become
+more clear.</P>
+
+<P>Finally, a simple <I>main()</I> function will provide our program loop.
+After any program initiallization, it will enter an infinite loop which
+waits for connection attempts to the Acceptor or data &quot;events&quot;
+on the EventHandler.</P>
+
+<P>
+<HR WIDTH="100%"></P>
+
+<P>Before we continue, I need to introduce one more ACE concept: the Reactor.
+</P>
+
+<P>I don't want to go into great detail at this time on what the Reactor
+is, what it does and how it does it but it is necessary for you to understand
+the basic function of a reactor because it is going to be in the first
+piece of code you see.</P>
+
+<P>Briefly:<BR>
+The reactor is an object which reacts when things happen to other objects.
+These things are called <I>events</I>. The <I>other objects</I> are communications
+objects which you have <I>registered</I> with the reactor. At the time
+of registration, you also specify which events you are interested in. The
+reactor is notified by the operating system when the events of interest
+occur within the registered objects. The reactor then uses member functions
+of the registered object to process the event. Notice that the reactor
+doesn't care what happens because of the event. It is the object's responsibility
+to process the event correctly. The reactor simply notifies the object
+of the event.</P>
+
+<P>Why use the reactor?</P>
+
+<P>That will become clear as the tutorial progresses. For now, however,
+a brief answer would be this: it allows multiple simultaneous client connections
+to be processed efficiently by a single-threaded server. </P>
+
+<P>Servers have traditionally created a separate thread or process for
+each client served. For large-volume services (such as telnet and ftp)
+this is appropriate. However, for small-volume services the overhead of
+process creation far outweighs the actual work being done. So... folks
+begin using threads instead of processes to handle the clients. This is
+good also but still, in some cases, the overhead is too much to bear. Instead,
+why not have a single thread handle several clients and use a more intelligent
+load-balancing methodology than one-thread-or-process-per-client?
+<i>Caveat: Handling all requests in one thread of one process is really
+only good when the requests can be handled almost instantaneously.</i>
+</P>
+
+<P>This is where the reactor's power and flexibility come into play. The
+developer can begin as a simple, single-threaded application that is later
+modified to thread-per-client, process-per-client or thread-pool solution.
+<P>
+If all of this is gibberish & makes you think that ACE is way to hard to
+learn, don't worry. We'll go into all the details & explain as we go.
+I only went into all of this so that it can kick around in the back of your
+mind until you need it later.
+<P>
+<HR WIDTH="100%"></P>
+
+<CENTER><P>[<A HREF="..">Tutorial Index</A>] [<A HREF="page02.html">Continue
+This Tutorial</A>] </P></CENTER>
+
+</BODY>
+</HTML>
diff --git a/docs/tutorials/001/page02.html b/docs/tutorials/001/page02.html
new file mode 100644
index 00000000000..24672f85cbf
--- /dev/null
+++ b/docs/tutorials/001/page02.html
@@ -0,0 +1,121 @@
+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 3.2//EN">
+<HTML>
+<HEAD>
+ <TITLE>ACE Tutorial 001</TITLE>
+ <META NAME="GENERATOR" CONTENT="Mozilla/3.01Gold (Win95; I) [Netscape]">
+ <META NAME="Author" CONTENT="James CE Johnson">
+ <META NAME="Description" CONTENT="A first step towards using ACE productively">
+</HEAD>
+<BODY text = "#000000" link="#000fff" vlink="#ff0f0f" bgcolor="#ffffff">
+
+
+<CENTER><P><B><FONT SIZE=+2>ACE&nbsp;Tutorial 001<BR>
+A Beginners Guide to Using the ACE&nbsp;Toolkit</FONT></B></P></CENTER>
+
+<P>
+<HR WIDTH="100%"></P>
+
+<P>From here, I want to move on to the main program loop. In a way, we're
+starting at the final product when we do this, but it is a very simple
+piece of code and a good place to start.</P>
+
+<P>The main program is really quite simple. The real work is done in the
+ACE derived classes.</P>
+
+<UL>
+<PRE>1. #include &quot;acceptor.h&quot;
+
+2. ACE_Reactor g_reactor;
+
+3. const unsigned int PORT = 10000;
+
+4. main()
+{
+ 5. ACE_INET_Addr addr(PORT);
+
+ 6. Client_Acceptor * ca = new Client_Acceptor(addr);
+
+ 7. g_reactor.register_handler(ca,ACE_Event_Handler::READ_MASK);
+
+ 8. for(;;) g_reactor.handle_events();
+
+ 9. return(0);
+}
+</PRE>
+</UL>
+
+<P>Here's a blow-by-blow account of what's being done:</P>
+
+<OL>
+<LI>Include the header file where our client acceptor is defined.</LI>
+
+<LI>For simplicity, we create our reactor in the global address space.
+In later tutorials we will do something more clever and appropriate. However,
+the purpose of this tutorial is to introduce a connection acceptance and
+handling, not the full capabilities of a reactor.</LI>
+
+<LI>A TCP/IP server can listen to only one <I>port </I>for connection requests.
+Well-known services can always be found at the same address. Lesser-known
+services are generally told where to listen by a configuration file or
+command-line parameter. For this example, we're satisfied with simply hard-coding
+a random but known value.</LI>
+
+<LI>Define the program entry point. Obviously, we are ignoring any command
+line parameters at this point. We may explore other options later.</LI>
+
+<LI>Like the Reactor, I'm skimming over the details of the <I>ADDR</I>
+object. What it provides is an abstraction for addressing services in the
+network. All we need to know at this point is that we are creating an address
+object which specifies the TCP/IP&nbsp;<I>port</I> on which the server
+will listen for new connection requests.</LI>
+
+<LI>Using the address object created above, we now create an acceptor object.
+This is all it takes to create the TCP/IP&nbsp;server and get it ready
+to listen on the specified port. As I understand it, no connections will
+yet be established because the object isn't &quot;open for business&quot;
+at this time. Which brings us to the next line...</LI>
+
+<LI>where the acceptor object is registered with the reactor. Upon registration,
+the reactor <I>open</I>s the object. For an acceptor, this means that client
+requests for connection will now be allowed. In the registration, we also
+tell the reactor that we are interested in <I>read</I> events. A read event
+for an acceptor is a request for connection. When the reactor sees one
+of these events, it will invoke the <I>handle_input</I> member function
+of the acceptor object. The <I>handle_input</I> function will then do whatever
+is necessary to deal with the new connection request. This is discussed
+in detail on the next page of this tutorial.</LI>
+
+<LI>The reactor's <I>handle_events</I> member function is responsible for
+looking at all registered objects and invoking their member function when
+anything of interest occurs. When an event is processed, the <I>handle_events
+</I>function returns. In order to get all events, we embed this in an infinite
+loop.</LI>
+
+<LI>This is redundant since the <I>handle_events</I> infinite loop will
+never exit. Some compilers will complain if it isn't there though, so in
+it goes.</LI>
+</OL>
+
+<P>As I said, the main program is really quite simple:</P>
+
+<UL>
+<LI>Create an address for the <I>port</I> we want to listen to</LI>
+
+<LI>Create an acceptor which listens on that address</LI>
+
+<LI>Register the acceptor with a reactor to respond to the connection requests</LI>
+
+<LI>Enter an infinite loop to let the reactor handle the events</LI>
+</UL>
+
+<P>On the next page, we will take a look at the acceptor and how it responds
+to new connection requests.</P>
+
+<P>
+<HR WIDTH="100%"></P>
+
+<CENTER><P>[<A HREF="../../Tutorial">Tutorial Index</A>] [<A HREF="page01.html">Previous
+Page</A>] [<A HREF="page03.html">Continue This Tutorial</A>] </P></CENTER>
+
+</BODY>
+</HTML>
diff --git a/docs/tutorials/001/page03.html b/docs/tutorials/001/page03.html
new file mode 100644
index 00000000000..836ba7c1ea8
--- /dev/null
+++ b/docs/tutorials/001/page03.html
@@ -0,0 +1,285 @@
+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 3.2//EN">
+<HTML>
+<HEAD>
+ <TITLE>ACE Tutorial 001</TITLE>
+ <META NAME="GENERATOR" CONTENT="Mozilla/3.01Gold (Win95; I) [Netscape]">
+ <META NAME="Author" CONTENT="James CE Johnson">
+ <META NAME="Description" CONTENT="A first step towards using ACE productively">
+</HEAD>
+<BODY text = "#000000" link="#000fff" vlink="#ff0f0f" bgcolor="#ffffff">
+
+
+<CENTER><P><B><FONT SIZE=+2>ACE&nbsp;Tutorial 001<BR>
+A Beginners Guide to Using the ACE&nbsp;Toolkit</FONT></B></P></CENTER>
+
+<P>
+<HR WIDTH="100%"></P>
+
+<P>Now we begin to look at the acceptor object.</P>
+
+<P>I will present the entire object header file first and then disect it
+as with <I>main()</I>.</P>
+
+<UL>
+<PRE>1. #include &lt;stdio.h&gt;
+
+2. #include &quot;ace/Reactor.h&quot;
+3. #include &quot;ace/Event_Handler.h&quot;
+4. #include &quot;ace/SOCK_Acceptor.h&quot;
+5. #include &quot;ace/SOCK_Stream.h&quot;
+6. #include &quot;ace/INET_Addr.h&quot;
+
+7. #include &quot;logger.h&quot;
+
+
+8. extern ACE_Reactor g_reactor;
+
+9. class Client_Acceptor : public ACE_Event_Handler
+ {
+
+10. public :
+
+11. Client_Acceptor( const ACE_INET_Addr &amp;addr) : acceptor_(addr) {
+12. if( ! (fp = fopen(&quot;acceptor&quot;,&quot;w+&quot;)) )
+13. fp = stderr;
+
+14. fprintf(fp,&quot;Constructed\n&quot;);
+ }
+
+15. virtual int handle_exception(ACE_HANDLE handle)
+ {
+16. fprintf(fp,&quot;Exception\n&quot;);
+17. return(-1);
+ }
+
+18. virtual int handle_input(ACE_HANDLE handle)
+ {
+19. ACE_SOCK_Stream new_connection;
+
+20. this-&gt;acceptor_.accept(new_connection);
+
+21. Logging_Handler *cli_handler = new Logging_Handler(new_connection);
+
+22. fprintf(fp,&quot;Got New Connection\n&quot;);
+
+23. int foo = g_reactor.register_handler(cli_handler,ACE_Event_Handler::RWE_MASK);
+24. return( foo );
+ }
+
+25. virtual ACE_HANDLE get_handle(void) const
+ {
+26. fprintf(fp,&quot;Providing Handle\n&quot;);
+27. return this-&gt;acceptor_.get_handle();
+ }
+
+28. virtual void handle_close(void)
+ {
+29. this-&gt;acceptor_.close();
+30. fprintf(fp,&quot;Closing\n&quot;);
+ }
+
+31. private :
+32. ACE_SOCK_Acceptor acceptor_;
+33. FILE * fp;
+34. };
+
+</PRE>
+</UL>
+
+<P>Here's a blow-by-blow account of what's being done:</P>
+
+<OL START=1>
+<LI>Include the standard I/O&nbsp;system header file. I only need this
+so that I&nbsp;can use <I>fprintf</I> stuff for the logging function. In
+reality we would probably talk to a database or something.</LI>
+
+<LI>Bring in the ACE headers. Don't worry about the details here.</LI>
+</OL>
+
+<OL START=7>
+<LI>Bring in the definition of the <I>logger</I> object. The logger will
+handle connections after our acceptor has accepted the connection. We'll
+look at that on the next page.</LI>
+
+<LI>Provide quick access to the reactor object. Later tutorials will be
+more clever than this...</LI>
+
+<LI>Derive our new acceptor object from the ACE_Event_Handler base-class.
+The event handler object is designed to work with the reactor. When an
+event handler is registered with a reactor, the reactor uses member functions
+of the event handler object to gain access to the underlying connection
+<I>handle.</I> We saw this registration process in the previous example
+when the acceptor object was registered with the reactor in the <I>main()</I>
+function. On Unix-type systems, the reactor will then use the <I>select</I>
+system call to wait for activity on the handle (on Win32, <I>WaitForMultipleObjects</I>
+is used instead). Once activity is detected on the handle by the reactor,
+different member functions of the event handler are invoked to process
+the activity. We'll see these in the lines below.</LI>
+
+<LI>Most of the object is going to be public. When we get a little better
+at what we're doing, we can try to make it safer by declaring some of these
+protected. Most of them can never be private however. Notice at this point
+how each of the functions is declared to be a virtual. This MUST be done
+so that if we later derive a class from here the runtime environment will
+get the member function of the derived class instead of that of the baseclass.</LI>
+
+<LI>The object constructor is the only non-virtual function. We may find
+out later that it should have been virtual! Anyway, we take the single
+parameter, a reference to an address object, and use it to initialize our
+<I>acceptor_</I> object. This is the object which will actually listen
+for client connections. There is a discussion below about why the Acceptor
+is a member of our object rather than it's base class.</LI>
+
+<LI>Remove the gag from the object by giving it somewhere to write debug
+information to. We'll use this file pointer throughout the object to keep
+track of it's internal activities.</LI>
+
+<LI>Fall back to <I>stderr</I> if we failed to open our output file.</LI>
+
+<LI>Status message (duh).</LI>
+
+<LI>The <I>handle_exception</I> member function will be called by the reactor
+if an exception is noticed on the handle associated with this object. In
+the case of a connected socket, an exception is generally caused when the
+remote side closes the connection. In the case of a listening socket, it
+could indicate som rare and strange network failure. See the <I>man</I>
+pages for <I>accept</I> and <I>listen</I> if you really care. For our purposes,
+if we get an exception on our acceptor then we return <I>-1</I> to the
+reactor which tells it we're out of commission. At that point the reactor
+will invoke our <I>close</I> funtion and shut us down.</LI>
+
+<LI>Display notification of the error.</LI>
+
+<LI>Return -1 to tell the reactor that we should be shut down.</LI>
+
+<LI>The <I>handle_input</I> method is called by the reactor whenever our
+handle has some data available for us to process. The actual handle is
+passed into the function but we won't be using it because we know it MUST
+be the <I>acceptor_</I> member object. We could compare the two as a safety
+check though.</LI>
+
+<LI>Now we are creating a new connection. It will be this connection which
+we use to communicate with the client. This will free up the acceptor to
+listen for more connection requests. Because the acceptor as a <I>SOCK
+</I>type object we need to create the connection as a <I>SOCK</I> also.
+An <I>ACE_SOCK_Stream</I> will provide us with an end-to-end connection
+similar to a pipe. This gives us the guarantee that any data we send or
+receive will be complete and in the correct order. An <I>ACE_SOCK_Dgram</I>
+could be used if we don't mind missing some packets or receiving them out
+of order.</LI>
+
+<LI>The <I>acceptor_</I> member object is now told to accept the client
+connection and attach it to the new <I>ACE_SOCK_Stream</I> object we just
+created. This is what frees up the acceptor to listen for more new connections.
+If you don't <I>accept</I> the connection, you cannot read the client's
+data and new clients cannot connect. In fact, after a timeout, the client
+which caused this <I>handle_input</I> callback will give up and assume
+the connection failed.</LI>
+
+<LI>Up to this point, we haven't done anything very specific with regards
+to our application. Here, however, we finally create a <I>logger</I> object
+to handle the connection. The logger object is something we defined in
+<I>logger.h</I>. It is given an <I>ACE_SOCK_Stream</I> object on which
+it will communicate. This is the <B>only</B> application-specific code
+you will find in the <I>Client_Acceptor</I> object we are developing here.</LI>
+
+<LI>Announce the new connection. We could use member functions of <I>new_connection</I>
+to report either of the local and remote systems' addresses and names.</LI>
+
+<LI>Finally, we register our <I>Logging_Handler</I> with our reactor. This
+tells the reactor about our new connection and tells it who to inform when
+there is activity on the connection. Note that we use the <I>RWE</I> mask
+so that we get notification when the connection has data for us to read,
+is available for us to write upon* and when it takes an error. (* Because
+of network buffers and such, you can't necessarily write on a connection
+anytime you want. At times, a <I>write</I> operation on a connection will
+fail or partially fail due to full buffers or some other network issue.
+When that happens, you must cache the remaining data to be written and
+wait for the write-notification event.)</LI>
+
+<LI>Return the result of registering the new connection. If the registration
+failed for some reason, this will cause the <I>handle_input</I> to fail
+and, ultimately, shut down the server. There is probably a much better
+way to handle this but it serves our purposes at the moment.</LI>
+
+<LI><I>get_handle</I> provides an interface layer between the reactor with
+which we're registered and the connection we wish the reactor to operate
+on. The reactor does it's job by monitoring one or more <I>handles</I>.
+In the Unix world, these are simply file descriptors. The <I>get_handle</I>
+method of a communcations object such as our <I>acceptor_</I> returns the
+underlying socket file descriptor associated with the connection. Because
+other OSes work differently, however, the <I>get_handle</I> method provides
+insulation for the programmer. By doing this, the programmer has the option
+of registering many types of objects with a reactor: disk-based file, serial
+port, intra-process pipes, etc...</LI>
+
+<LI>Progress notification.</LI>
+
+<LI>Return the handle of the actual communcation's object.</LI>
+
+<LI>Similar to <I>get_handle</I>, the <I>handle_close</I> is a wrapper
+that allows the reactor to close a connection object. Again, this does
+not have to be an IPC object, it could be anything that supports basic
+open/read/write/close functionality. What we're doing here is shutting
+down the acceptor. You would do this when you want to bring down or pause
+the server.</LI>
+
+<LI>Perform the actual close operation.</LI>
+
+<LI>Another notification</LI>
+
+<LI>Now we begin our brief section of private data. In a real application
+this might be <I>protected</I> instead so that a derived object would have
+direct access to the data members. On the other hand, we may not want that...</LI>
+
+<LI>The <I>acceptor_</I> member object is where all of the action centers.
+It is this object which abstracts all of the socket-level mess necessary
+to listen for client connection requests.</LI>
+
+<LI>The file pointer is our simple way of reporting progress throught the
+program and logging activity from the client.</LI>
+
+<LI>All Done.</LI>
+</OL>
+
+<P>It is important to notice here that we have done very little application-specifc
+code in developing this object. In fact, if we take out the progress information,
+the only app-specific code is when we create the new <I>Logging_Handler</I>
+object to give to the <I>accept</I> function. You may begin to wonder why
+there isn't a C++&nbsp;template that does all of this coding for you. Actually,
+the ACE toolkit happens to have one handy:</P>
+
+<UL>
+<P>typedef ACE_Acceptor &lt;<I>YourHandlerClass</I>, ACE_SOCK_ACCEPTOR&gt;
+<I>YourAcceptorClass</I>;</P>
+</UL>
+
+<P>We would have used it like this:</P>
+
+<UL>
+<P>typedef ACE_Acceptor &lt;Logging_Handler, ACE_SOCK_ACCEPTOR&gt; Client_Acceptor;</P>
+</UL>
+
+<P>This will create a piece of code similar to what I've shown above. The
+primary difference is that the <I>handle_input </I>function created by
+the template does NOT register the handler with the reactor. In the long-run,
+that is good for us because we can then move that logic into the <I>open</I>
+function of the <I>Logging_Handler</I> and use a completely-generic acceptor.</P>
+
+<P>Now that we know how to accept a connection request, let's move on to
+the next page where we learn how to handle the actual connection. Even
+though we just learned about this cool template thing, we will continue
+to use the &quot;hand-written&quot; acceptor developed above. As I mentioned,
+the only difference will be in the <I>open</I> function of the connection
+handler anyway.</P>
+
+<P>
+<HR WIDTH="100%"></P>
+
+<CENTER><P>[<A HREF="..">Tutorial
+Index</A>] [<A HREF="page02.html">Previous
+Page</A>] [<A HREF="page04.html">Continue
+This Tutorial</A>] </P></CENTER>
+
+</BODY>
+</HTML>
diff --git a/docs/tutorials/001/page04.html b/docs/tutorials/001/page04.html
new file mode 100644
index 00000000000..292e7f09c16
--- /dev/null
+++ b/docs/tutorials/001/page04.html
@@ -0,0 +1,239 @@
+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 3.2//EN">
+<HTML>
+<HEAD>
+ <TITLE>ACE Tutorial 001</TITLE>
+ <META NAME="GENERATOR" CONTENT="Mozilla/3.01Gold (Win95; I) [Netscape]">
+ <META NAME="Author" CONTENT="James CE Johnson">
+ <META NAME="Description" CONTENT="A first step towards using ACE productively">
+</HEAD>
+<BODY text = "#000000" link="#000fff" vlink="#ff0f0f" bgcolor="#ffffff">
+
+
+<CENTER><P><B><FONT SIZE=+2>ACE&nbsp;Tutorial 001<BR>
+A Beginners Guide to Using the ACE&nbsp;Toolkit</FONT></B></P></CENTER>
+
+<P>
+<HR WIDTH="100%"></P>
+
+<P>Now we begin to look at the acceptor object.</P>
+
+<P>I will present the entire object header file first and then disect it
+as with <I>main()</I>.</P>
+
+<UL>
+<PRE>
+1. #include &lt;stdio.h&gt;
+
+2. #include &quot;ace/Reactor.h&quot;
+3. #include &quot;ace/SOCK_Acceptor.h&quot;
+4. #include &quot;ace/SOCK_Stream.h&quot;
+5. #include &quot;ace/INET_Addr.h&quot;
+
+
+
+6. class Logging_Handler : public ACE_Event_Handler
+ {
+7. public:
+
+8. Logging_Handler(ACE_SOCK_Stream &amp;cs) : client_stream_(cs)
+ {
+9. if( ! (fp = fopen(&quot;logger&quot;,&quot;w+&quot;)) )
+10. fp = stderr;
+11. fprintf(fp,&quot;Constructed\n&quot;);
+ }
+
+12. virtual int handle_exception(ACE_HANDLE handle)
+ {
+13. fprintf(fp,&quot;Exception\n&quot;);
+14. return(-1);
+ }
+
+15. virtual int handle_input(ACE_HANDLE handle)
+ {
+16. char buf[128];
+
+17. if( this-&gt;client_stream_.recv(buf,sizeof buf) &lt; 1 )
+ {
+18. fprintf(fp,&quot;Bad Read\n&quot;);
+19. return(-1);
+ }
+20. else
+ {
+21. fprintf(fp,&quot;%20.20s\n&quot;,buf);
+ }
+22. return(strlen(buf));
+ }
+
+23. virtual ACE_HANDLE get_handle(void) const
+ {
+24. fprintf(fp,&quot;providing handle\n&quot;);
+25. return this-&gt;client_stream_.get_handle();
+ }
+
+26. virtual int handle_close(ACE_HANDLE h, ACE_Reactor_Mask m)
+ {
+27. fprintf(fp,&quot;closing\n&quot;);
+28. delete this;
+29. return(0);
+ }
+
+30. virtual int close(void)
+ {
+31. return this-&gt;handle_close(ACE_INVALID_HANDLE,ACE_Event_Handler::RWE_MASK);
+32. };
+
+33. protected:
+34. ~Logging_Handler(void)
+ {
+35. fprintf(fp,&quot;Destruction\n&quot;);
+36. };
+
+37. private:
+38. ACE_SOCK_Stream client_stream_;
+39. FILE * fp;
+40. };
+
+
+</PRE>
+</UL>
+
+<P>Here's a blow-by-blow account of what's being done:</P>
+
+<OL>
+<LI>Necessary for the <I>fopen</I> and such.</LI>
+
+<LI>We don't actually use a reactor in this object. If we had used the
+template to create our acceptor though, we would have to register ourselves
+with the reactor in our <I>open</I> function.</LI>
+
+<LI>This just shouldn't be here. Again, though, if we wanted to use the
+template to create the acceptor then we would probably do so after the
+object definition instead of dedicating an entire file to it. So, with
+that in mind, we would need the acceptor header or at least one like it.</LI>
+
+<LI>This contains the objects we need to create a connected socket object.
+Where we used an ACE_SOCK_Acceptor object in our acceptor we will use an
+ACE_SOCK_Stream here.</LI>
+
+<LI>This has some handy objects that allow us to get to the address components
+of our connection.</LI>
+
+<LI>Like the acceptor, we derive a new class from the <I>ACE_Event_Handler</I>.
+This gives a signature to the reactor we're registered with so that it
+can cause us to react to activity on the connection.</LI>
+
+<LI>Begin the public section of our object...</LI>
+
+<LI>We are constructed by the acceptor when a new client connection request
+is accepted. At the same time, the acceptor object creates a new <I>SOCK_Stream</I>
+on which we will communicate. That new <I>SOCK_Stream</I> is passed to
+us here so that we can initialize our<I> client_stream_</I> member object.</LI>
+
+<LI>Open a file we can write our status and log information to. Whatever
+the client sends us we will write here.</LI>
+
+<LI>Default to <I>stderr</I> if the open fails for some reason.</LI>
+
+<LI>Announce our birth.</LI>
+
+<LI>An exception on a socket generally indicates that the connection closed
+unexpectedly. There are some cases when this may not be fatal (eg -- invoking
+a reactor's <I>notify()</I> method) but for our simple tutorial, we assume
+that any exception is fatal.</LI>
+
+<LI>Log the action</LI>
+
+<LI>Return <I>-1</I> to the reactor to indicate that we should be <I>close</I>ed
+and destroyed.</LI>
+
+<LI><I>handle_input</I> is called by the reactor when there is data to
+be read from the connection. The <I>handle</I> parameter is the handle
+on which the data is present. Since we know the handle is supposed to be
+our <I>client_stream_</I> member object, we don't really need the parameter
+except as a double-check.</LI>
+
+<LI>Create a space for reading the data. We will do a simple-minded receive
+here but a real application could do any number of things.</LI>
+
+<LI>Invoke the <I>recv</I> member function of teh <I>client_stream_</I>
+object. As shown, it will get up to 128 bytes from the connection. Again,
+our simple example won't be stressing this particular limit. Another handy
+<I>SOCK_Stream</I> function is <I>recv_n</I> which will receive an exact
+amount of data even if it isn't all immediately available.</LI>
+
+<LI>We must read at least on byte. If there were none available then the
+reactor wouldn't have invoked the <I>handle_input</I> function in the first
+place. So, if we don't get anything there must be something wrong with
+the connection. Report this to the user.</LI>
+
+<LI>Return <I>-1</I> to get ourselves shut down.</LI>
+
+<LI>However, if the receive operation was successful...</LI>
+
+<LI>Format the received data and write it to the log file.</LI>
+
+<LI>Return a positive number to the reactor. Anything is ok (I think) but
+for giggles, we return the number of bytes received.</LI>
+
+<LI>Wrapper method allowing the reactor to access the connection handle.
+Again, this is necessary because the reactor can only work with file handles
+(aka &quot;file descriptors&quot;).</LI>
+
+<LI>Status message...</LI>
+
+<LI>Provide the handle when requested.</LI>
+
+<LI><I>handle_close</I> will be called by the reactor when it is time to
+shut down the connection. Among the reasons for shutdown is a <I>-1</I>
+return from any of the handlers called by the reactor.</LI>
+
+<LI>Another status message</LI>
+
+<LI>This is a terribly clever and handy thing. There is supposed to be
+some C++&nbsp;magic that will ensure an object can only be instantiated
+dynamically (ie -- via the <I>new</I> operator). Once you guarante that
+then <I>delete this</I> is possible.</LI>
+
+<LI>Return a success status to the reactor now that everything is closed
+correctly.</LI>
+
+<LI>A simple wrapper to <I>handle_close.</I>
+This is only here so that the acceptor can close us down if there is
+an error opening us up...
+</LI>
+
+<LI>Begin the protected part of our object.</LI>
+
+<LI>This helps to ensure that dynamic allocation we were talking about.</LI>
+
+<LI>Yet another status message.</LI>
+
+<LI>Begin the private section of the object.</LI>
+
+<LI>The <I>client_stream</I>_ is what we use to communicate. It can be
+any type of connection object or even, if we're not doing IPC, it could
+be a file descriptor open to a serial port or a data file.</LI>
+
+<LI>A handy file pointer where we can write the status messages and data
+from the client.</LI>
+
+<LI>All done.</LI>
+</OL>
+
+<P>Now that we know how to accept a connection request, let's move on to
+the next page where we learn how to handle the actual connection. Even
+though we just learned about this cool template thing, we will continue
+to use the &quot;hand-written&quot; acceptor developed above. As I mentioned,
+the only difference will be in the <I>open</I> function of the connection
+handler anyway.</P>
+
+<P>
+<HR WIDTH="100%"></P>
+
+<CENTER><P>[<A HREF="..">Tutorial
+Index</A>] [<A HREF="page03.html">Previous
+Page</A>] [<A HREF="page05.html">Continue
+This Tutorial</A>] </P></CENTER>
+
+</BODY>
+</HTML>
diff --git a/docs/tutorials/001/page05.html b/docs/tutorials/001/page05.html
new file mode 100644
index 00000000000..a653ef35e99
--- /dev/null
+++ b/docs/tutorials/001/page05.html
@@ -0,0 +1,53 @@
+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 3.2//EN">
+<HTML>
+<HEAD>
+ <TITLE>ACE Tutorial 001</TITLE>
+ <META NAME="GENERATOR" CONTENT="Mozilla/3.01Gold (Win95; I) [Netscape]">
+ <META NAME="Author" CONTENT="James CE Johnson">
+ <META NAME="Description" CONTENT="A first step towards using ACE productively">
+</HEAD>
+<BODY text = "#000000" link="#000fff" vlink="#ff0f0f" bgcolor="#ffffff">
+
+
+<CENTER><P><B><FONT SIZE=+2>ACE&nbsp;Tutorial 001<BR>
+A Beginners Guide to Using the ACE&nbsp;Toolkit</FONT></B></P></CENTER>
+
+<P>
+<HR WIDTH="100%"></P>
+
+<P>This concludes the first tutorial on using ACE. We've learned how to
+create a simple server without knowing very much about network programming.
+</P>
+
+<P>The code used in this tutorial is for illustration purposes. That means
+it may or may not work. I have created a working example which is more
+or less the same as the code in the tutorial. The primary difference is
+that the working code doesn't do all that mucking around with <I>FILE</I>
+pointers and status messages. </P>
+
+<P>You can download all of the <A HREF="Source.tgz">source</A> or individual
+files:</P>
+
+<UL>
+<LI><A HREF="00SetEnv">Environment Settings</A></LI>
+
+<LI><A HREF="Makefile">Makefile</A></LI>
+
+<LI><A HREF="server.cpp">main program</A></LI>
+
+<LI><A HREF="acceptor.h">acceptor object</A></LI>
+
+<LI><A HREF="logger.h">connection handler</A></LI>
+</UL>
+
+<P>(The source is a gzip'ed tar file which can be unpacked using <I>winzip</I>
+or the Unix command <I>tar -xvzf filename</I>.)</P>
+
+<P>
+<HR WIDTH="100%"></P>
+
+<CENTER><P>[<A HREF="..">Tutorial Index</A>] [<A HREF="page04.html">Previous
+Page</A>] </P></CENTER>
+
+</BODY>
+</HTML>
diff --git a/docs/tutorials/001/server.cpp b/docs/tutorials/001/server.cpp
new file mode 100644
index 00000000000..09e21bc6b74
--- /dev/null
+++ b/docs/tutorials/001/server.cpp
@@ -0,0 +1,34 @@
+// $Id$
+
+#include "ace/Reactor.h"
+ACE_Reactor * g_reactor;
+
+#include "acceptor.h"
+
+static sig_atomic_t finished = 0;
+extern "C" void handler (int) { finished = 1; }
+
+static const u_short PORT = ACE_DEFAULT_SERVER_PORT;
+
+int
+main (int argc, char *argv[])
+{
+ g_reactor = new ACE_Reactor;
+
+ ACE_Sig_Action sa ((ACE_SignalHandler) handler, SIGINT);
+
+ ACE_INET_Addr addr (PORT);
+ Logging_Acceptor * peer_acceptor = new Logging_Acceptor(addr);
+
+ if (g_reactor-> register_handler (peer_acceptor, ACE_Event_Handler::READ_MASK) == -1)
+ ACE_ERROR_RETURN ((LM_ERROR, "registering service with ACE_Reactor\n"), -1);
+
+ ACE_DEBUG ((LM_DEBUG, "(%P|%t) starting up server logging daemon\n"));
+
+ while (!finished)
+ g_reactor-> handle_events ();
+
+ ACE_DEBUG ((LM_DEBUG, "(%P|%t) shutting down server logging daemon\n"));
+
+ return 0;
+}
diff --git a/docs/tutorials/002/00SetEnv b/docs/tutorials/002/00SetEnv
new file mode 100644
index 00000000000..33ba8135007
--- /dev/null
+++ b/docs/tutorials/002/00SetEnv
@@ -0,0 +1,2 @@
+export WRAPPER_ROOT=/local/src/ACE/ACE_wrappers
+export LD_LIBRARY_PATH=$WRAPPER_ROOT/ace:$LD_LIBRARY_PATH
diff --git a/docs/tutorials/002/Makefile b/docs/tutorials/002/Makefile
new file mode 100644
index 00000000000..ec3e3bd243c
--- /dev/null
+++ b/docs/tutorials/002/Makefile
@@ -0,0 +1,42 @@
+#----------------------------------------------------------------------------
+# $Id$
+#
+# Makefile for the Reactor version of the Server Logging Daemon
+#----------------------------------------------------------------------------
+
+#----------------------------------------------------------------------------
+# Local macros
+#----------------------------------------------------------------------------
+
+BIN = server
+
+VLDLIBS = $(LDLIBS:%=%$(VAR))
+
+BUILD = $(VBIN)
+
+#----------------------------------------------------------------------------
+# Include macros and targets
+#----------------------------------------------------------------------------
+
+include $(WRAPPER_ROOT)/include/makeinclude/wrapper_macros.GNU
+include $(WRAPPER_ROOT)/include/makeinclude/macros.GNU
+include $(WRAPPER_ROOT)/include/makeinclude/rules.common.GNU
+include $(WRAPPER_ROOT)/include/makeinclude/rules.nonested.GNU
+include $(WRAPPER_ROOT)/include/makeinclude/rules.lib.GNU
+include $(WRAPPER_ROOT)/include/makeinclude/rules.bin.GNU
+include $(WRAPPER_ROOT)/include/makeinclude/rules.local.GNU
+
+#----------------------------------------------------------------------------
+# Local targets
+#----------------------------------------------------------------------------
+
+#----------------------------------------------------------------------------
+# Dependencies
+#----------------------------------------------------------------------------
+
+# DO NOT DELETE THIS LINE -- g++dep uses it.
+# DO NOT PUT ANYTHING AFTER THIS LINE, IT WILL GO AWAY.
+
+
+
+# IF YOU PUT ANYTHING HERE IT WILL GO AWAY
diff --git a/docs/tutorials/002/acceptor b/docs/tutorials/002/acceptor
new file mode 100644
index 00000000000..45409e4ec3e
--- /dev/null
+++ b/docs/tutorials/002/acceptor
@@ -0,0 +1,6 @@
+
+1. #include "ace/Acceptor.h"
+2. #include "ace/SOCK_Acceptor.h"
+
+3. typedef ACE_Acceptor <Logging_Handler, ACE_SOCK_ACCEPTOR> Logging_Acceptor;
+
diff --git a/docs/tutorials/002/handler b/docs/tutorials/002/handler
new file mode 100644
index 00000000000..d987f4c34ff
--- /dev/null
+++ b/docs/tutorials/002/handler
@@ -0,0 +1,81 @@
+
+1. #include "ace/SOCK_Acceptor.h"
+2. #include "ace/Reactor.h"
+
+
+3. class Logging_Handler : public ACE_Svc_Handler<ACE_SOCK_STREAM, ACE_NULL_SYNCH>
+ {
+
+ public:
+
+4. Logging_Handler (void)
+ {
+ }
+
+5. virtual void destroy (void)
+ {
+6. g_reactor->cancel_timer (this);
+7. this->peer ().close ();
+ }
+
+8. virtual int open (void *)
+ {
+9. ACE_INET_Addr addr;
+
+10. if (this->peer ().get_remote_addr (addr) == -1)
+11. return -1;
+12. else
+ {
+13. ACE_OS::strncpy (this->peer_name_, addr.get_host_name (), MAXHOSTNAMELEN + 1);
+
+14. if (g_reactor->register_handler(this, ACE_Event_Handler::READ_MASK) == -1)
+15. ACE_ERROR_RETURN ((LM_ERROR, "(%P|%t) can't register with reactor\n"), -1);
+
+16. else if (g_reactor->schedule_timer (this, (const void *) this, ACE_Time_Value (2), ACE_Time_Value (2)) == -1)
+17. ACE_ERROR_RETURN ((LM_ERROR, "can'(%P|%t) t register with reactor\n"), -1);
+
+18. else
+19. ACE_DEBUG ((LM_DEBUG, "(%P|%t) connected with %s\n", this->peer_name_));
+
+20. return 0;
+ }
+ }
+
+21. virtual int close (u_long)
+ {
+22. this->destroy ();
+23. return 0;
+ }
+
+ protected:
+
+24. virtual int handle_input (ACE_HANDLE)
+ {
+25. char buf[128];
+26. memset(buf,0,sizeof(buf));
+
+27. switch( this->peer().recv(buf,sizeof buf) )
+ {
+28. case -1:
+29. ACE_ERROR_RETURN ((LM_ERROR, "(%P|%t) %p bad read\n", "client logger"), -1);
+30. case 0:
+31. ACE_ERROR_RETURN ((LM_ERROR, "(%P|%t) closing log daemon (fd = %d)\n", this->get_handle ()), -1);
+32. default:
+33. ACE_DEBUG ((LM_DEBUG, "(%P|%t) from client: %s",buf));
+ }
+
+34. return 0;
+ }
+
+35. virtual int handle_timeout (const ACE_Time_Value &tv, const void *arg)
+ {
+36. ACE_ASSERT (arg == this);
+37. ACE_DEBUG ((LM_DEBUG, "(%P|%t) handling timeout from this = %u\n", this));
+38. return 0;
+ }
+
+ private:
+
+39. char peer_name_[MAXHOSTNAMELEN + 1];
+
+ };
diff --git a/docs/tutorials/002/main b/docs/tutorials/002/main
new file mode 100644
index 00000000000..36c67561463
--- /dev/null
+++ b/docs/tutorials/002/main
@@ -0,0 +1,36 @@
+1. #include "ace/Reactor.h"
+
+2. ACE_Reactor * g_reactor;
+
+3. static sig_atomic_t finished = 0;
+4. extern "C" void handler (int) { finished = 1; }
+
+5. static const u_short PORT = ACE_DEFAULT_SERVER_PORT;
+
+6. int main (int argc, char *argv[])
+ {
+7. g_reactor = new ACE_Reactor;
+
+ // Acceptor factory.
+8. Logging_Acceptor peer_acceptor;
+
+9. if (peer_acceptor.open (ACE_INET_Addr (PORT)) == -1)
+10. ACE_ERROR_RETURN ((LM_ERROR, "%p\n", "open"), -1);
+
+11. else if (g_reactor->register_handler (&peer_acceptor, ACE_Event_Handler::READ_MASK) == -1)
+12. ACE_ERROR_RETURN ((LM_ERROR, "registering service with ACE_Reactor\n"), -1);
+
+13. ACE_Sig_Action sa ((ACE_SignalHandler) handler, SIGINT);
+
+ // Run forever, performing logging service.
+
+14. ACE_DEBUG ((LM_DEBUG, "(%P|%t) starting up server logging daemon\n"));
+
+ // Perform logging service until QUIT_HANDLER receives SIGINT.
+15. while ( !finished )
+16. g_reactor->handle_events ();
+
+17. ACE_DEBUG ((LM_DEBUG, "(%P|%t) shutting down server logging daemon\n"));
+
+18. return 0;
+ }
diff --git a/docs/tutorials/002/page01.html b/docs/tutorials/002/page01.html
new file mode 100644
index 00000000000..5bc3fc534a7
--- /dev/null
+++ b/docs/tutorials/002/page01.html
@@ -0,0 +1,57 @@
+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 3.2//EN">
+<HTML>
+<HEAD>
+ <TITLE>ACE Tutorial 002</TITLE>
+ <META NAME="GENERATOR" CONTENT="Mozilla/3.01Gold (Win95; I) [Netscape]">
+ <META NAME="Author" CONTENT="James CE Johnson">
+ <META NAME="Description" CONTENT="A first step towards using ACE productively">
+</HEAD>
+<BODY text = "#000000" link="#000fff" vlink="#ff0f0f" bgcolor="#ffffff">
+
+
+<CENTER><P><B><FONT SIZE=+2>ACE&nbsp;Tutorial 002<BR>
+Creating a Better Server </FONT></B></P></CENTER>
+
+<P>
+<HR WIDTH="100%"></P>
+
+<P>In this tutorial, we will build a little on what we learned in the first
+tutorial and add a few extras. In the end, we will have a better server
+object that is actually simpler and more maintainable than the one we created
+before.</P>
+
+<P>
+<HR WIDTH="100%"></P>
+
+<P>To begin, let's ask ourselves the same thing we did at the beginning
+of tutorial 001:</P>
+
+<UL>
+<P>What do you need to create a server?</P>
+</UL>
+
+<OL>
+<OL>
+<LI>Something which accepts connections from clients</LI>
+
+<LI>Something which handles established connections</LI>
+
+<LI>A main program loop that handles it all</LI>
+</OL>
+</OL>
+
+<P>Previously, we created a solution which addressed each one of these
+questions specifically. At the end of it all, we realized that our only
+application-specific coding was confined to the <I>handler</I> portion
+of the program. We hinted that there may be a way to eliminate hand-coding
+an <I>acceptor</I> each time we want to create a server. Here, we will
+explore that approach.</P>
+
+<P>
+<HR WIDTH="100%"></P>
+
+<CENTER><P>[<A HREF="..">Tutorial Index</A>] [<A HREF="page02.html">Continue
+This Tutorial</A>] </P></CENTER>
+
+</BODY>
+</HTML>
diff --git a/docs/tutorials/002/page02.html b/docs/tutorials/002/page02.html
new file mode 100644
index 00000000000..d7808d58c7d
--- /dev/null
+++ b/docs/tutorials/002/page02.html
@@ -0,0 +1,174 @@
+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 3.2//EN">
+<HTML>
+<HEAD>
+ <TITLE>ACE Tutorial 002</TITLE>
+ <META NAME="GENERATOR" CONTENT="Mozilla/3.01Gold (Win95; I) [Netscape]">
+ <META NAME="Author" CONTENT="James CE Johnson">
+ <META NAME="Description" CONTENT="A first step towards using ACE productively">
+</HEAD>
+<BODY text = "#000000" link="#000fff" vlink="#ff0f0f" bgcolor="#ffffff">
+
+
+<CENTER><P><B><FONT SIZE=+2>ACE&nbsp;Tutorial 002<BR>
+Creating a Better Server </FONT></B></P></CENTER>
+
+<P>
+<HR WIDTH="100%"></P>
+
+<P>The program is actually small enough to fit into a single source file.
+To make things a little easier to follow, though, I've broken it up into
+three parts: main, acceptor and handler. Each is presented with line numbers
+and description. Because it is a single file, you won't see <I>#include</I>
+directives you may expect. Wait 'till the final page and see the whole
+thing put together before you worry about things like that.</P>
+
+<P>
+<HR WIDTH="100%"></P>
+
+<P>We begin by looking at the main portion program:</P>
+
+<UL>
+<PRE>1. #include &quot;ace/Reactor.h&quot;
+
+2. ACE_Reactor * g_reactor;
+
+3. static sig_atomic_t finished = 0;
+4. extern &quot;C&quot; void handler (int) { finished = 1; }
+
+5. static const u_short PORT = ACE_DEFAULT_SERVER_PORT;
+
+6. int main (int argc, char *argv[])
+ {
+7. g_reactor = new ACE_Reactor;
+
+ // Acceptor factory.
+8. Logging_Acceptor peer_acceptor;
+
+9. if (peer_acceptor.open (ACE_INET_Addr (PORT)) == -1)
+10. ACE_ERROR_RETURN ((LM_ERROR, &quot;%p\n&quot;, &quot;open&quot;), -1);
+
+11. else if (g_reactor-&gt;register_handler (&amp;peer_acceptor, ACE_Event_Handler::READ_MASK) == -1)
+12. ACE_ERROR_RETURN ((LM_ERROR, &quot;registering service with ACE_Reactor\n&quot;), -1);
+
+13. ACE_Sig_Action sa ((ACE_SignalHandler) handler, SIGINT);
+
+ // Run forever, performing logging service.
+
+14. ACE_DEBUG ((LM_DEBUG, &quot;(%P|%t) starting up server logging daemon\n&quot;));
+
+ // Perform logging service until QUIT_HANDLER receives SIGINT.
+15. while ( !finished )
+16. g_reactor-&gt;handle_events ();
+
+17. ACE_DEBUG ((LM_DEBUG, &quot;(%P|%t) shutting down server logging daemon\n&quot;));
+
+18. return 0;
+ }</PRE>
+</UL>
+
+<P>
+<HR></P>
+
+<OL>
+<LI>The reactor is the only ACE object directly used by the main program.
+We bring in it's definition here.</LI>
+
+<LI>To keep things simple, we again have a global reactor object. This
+time, however, we are keeping a pointer to it. Since C++&nbsp;isn't too
+clear about initialization of global/static objects I chose to dynamically
+create the object in <I>main</I> rather than having it global.</LI>
+
+<LI><I>finished</I> is an atomic data type which we will use to tell us
+the server should exit. It will be set when the program receives an <I>interrupt</I>
+signal.</LI>
+
+<LI>This &quot;C&quot; function will process the <I>interrupt</I> signal
+if it is received by the program. All that it needs to do is set the <I>finished</I>
+flag which our main loop will look at as an indication to exit.</LI>
+
+<LI>The simple variable <I>PORT</I> is statically initialized to a default
+value. This is where the server will listen for new client connection requests.</LI>
+
+<LI>A typical <I>main</I> signature. Although we give ourselves access
+to the command-line arguments, we won't be using them. A more robust example
+might allow specifying the port number or other information via the command-line.</LI>
+
+<LI>The global reactor pointer is now initialized. We could have just as
+easily have chosen to create it on the stack and set <I>g_reactor</I> to
+point to the stack variable. Either way, it gives us more control than
+declaring it outside of <I>main</I>.</LI>
+
+<LI>Now, we create the object which will accept new client requests. Unlike
+the reactor, we did create this one on the stack. In the long run it really
+doesn't matter since Unix is very nice about cleaning up allocated memory
+when the program exits.</LI>
+
+<LI>We now use the acceptor's <I>open</I> member function to get it up
+and running. In the previous example, we passed the <I>port</I> object
+to the acceptor at construction time. This time around, we're passing it
+to <I>open</I> instead. Why? Well, we could have created a constructor
+to accept the <I>port</I> object but we're trying to use one of ACE's tools
+to create a totally generic acceptor. It turns out that that tool creates
+an acceptor that requires the port passed to <I>open</I> rather than the
+constructor. In the long run, this is a good thing because there is no
+good way for a constructor to return a failure. Since we need to know if
+the <I>SOCK_Acceptor</I> is initialized correctly, we are better off initializing
+it in a function that <B>can</B> return an error code. You'll also notice
+that we simply create and pass the <I>port</I> object in one step instead
+of creating an intermediate variable to handle it.</LI>
+
+<LI>We use <I>ACE_ERROR_RETURN</I> to get ourselves out if the <I>open</I>
+call fails. This is a handy and consistent method for reporting nasty things.</LI>
+
+<LI>If the <I>open</I> was successful we will get to here. It is now time
+to register the acceptor with the reactor so that the acceptor's member
+functions will be called when there is activity to be dealt with. Notice
+that we have to pass the address of the acceptor since we created the object
+on the stack instead of with <I>new</I>. Also notice that we're asking
+the reactor to only respond to <I>READ</I> type events. These will be client
+connection requests.</LI>
+
+<LI>Another call to <I>ACE_ERROR_RETURN</I> if the registration failed.</LI>
+
+<LI>An <I>ACE_Sig_Action</I> object is created and given the address of
+the <I>handle</I> &quot;C&quot;&nbsp;function declared above. With that
+function is associated the signal <I>SIGINT</I>. If the program receives
+this signal at any time, the <I>handle</I> function will be called. This
+is our way to cleanly exit the program. There is a much cleaner way to
+do this by creating an object which is registered with the reactor. However,
+I&nbsp;don't want to get into reactor-registered signal handlers at this
+time, so we're going with the easy-out.</LI>
+
+<LI><I>ACE_DEBUG</I> is another function like <I>ACE_ERROR_RETURN</I> that
+we can use to provide consistent messages to the user. Here, we just want
+to report that the program has started.</LI>
+
+<LI>Loop forever unless <I>finished</I> gets a non-zero value. Since the
+only way that can happen is by receipt of an <I>interrupt</I> signal, we
+will keep running until somebody <I>kill</I>s us with that (<I>kill -SIGINT&nbsp;process-id</I>).</LI>
+
+<LI>As always, allow the reactor to handle any events that are generated
+on it's registered event handlers.</LI>
+
+<LI>Announce our departure.</LI>
+
+<LI>Return a successful exit value to the operating system.</LI>
+</OL>
+
+<P>We got a little sloppy by not <I>delete</I>ing the reactor we dynamically
+allocated at the beginning of <I>main</I>. We really should do that for
+sake of completeness and neat programming. Even if we forget though, Unix
+is good about freeing up a program's memory (automatic and dynamically
+allocated)&nbsp;when the program exits.</P>
+
+<P>Now that our re-designed <I>main</I> is dealt with, we will describe
+our much-improved and easier to maintain acceptor object.</P>
+
+<P>
+<HR WIDTH="100%"></P>
+
+<CENTER><P>[<A HREF="../../Tutorial">Tutorial Index</A>] [<A HREF="page01.html">Previous
+Page</A>] [<A HREF="page03.html">Continue This Tutorial</A>] </P></CENTER>
+
+</BODY>
+</HTML>
diff --git a/docs/tutorials/002/page03.html b/docs/tutorials/002/page03.html
new file mode 100644
index 00000000000..38ed438ed18
--- /dev/null
+++ b/docs/tutorials/002/page03.html
@@ -0,0 +1,65 @@
+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 3.2//EN">
+<HTML>
+<HEAD>
+ <TITLE>ACE Tutorial 002</TITLE>
+ <META NAME="GENERATOR" CONTENT="Mozilla/3.01Gold (Win95; I) [Netscape]">
+ <META NAME="Author" CONTENT="James CE Johnson">
+ <META NAME="Description" CONTENT="A first step towards using ACE productively">
+</HEAD>
+<BODY text = "#000000" link="#000fff" vlink="#ff0f0f" bgcolor="#ffffff">
+
+
+<CENTER><P><B><FONT SIZE=+2>ACE&nbsp;Tutorial 002<BR>
+Creating a Better Server </FONT></B></P></CENTER>
+
+<P>
+<HR WIDTH="100%"></P>
+
+<P>This is what we do to create an acceptor from the ACE&nbsp;template:</P>
+
+<UL>
+<PRE>
+1. #include &quot;ace/Acceptor.h&quot;
+2. #include &quot;ace/SOCK_Acceptor.h&quot;
+
+3. typedef ACE_Acceptor &lt;Logging_Handler, ACE_SOCK_ACCEPTOR&gt; Logging_Acceptor;
+</PRE>
+</UL>
+
+<P>
+<HR></P>
+
+<P>Now, if you think that was difficult, you may as well give up now.</P>
+
+<OL>
+<LI>The <I>Acceptor</I> header file defines the template we're about to
+use. This is a totally generic object where all of the hard work as already
+been done.</LI>
+
+<LI>Because we want to accept connections on an <I>ACE_SOCK_Stream</I>,
+we have to pull in this header. It provides the API details that we will
+need.</LI>
+
+<LI>Finally, create a <I>Logging_Acceptor</I> object based on the <I>ACE_Acceptor</I>
+template. The first parameter <I>Logging_Handler</I> is an object we will
+develop on the next page. This object will be created by the template-generated
+code whenever a new connection request is accepted. The second parameter
+tells the template what kind of acceptor to create. It is most important
+that the first-parameter object and the second parameter be consistent
+in the connetion types used.</LI>
+</OL>
+
+<P>Obviously we're doing things a bit out of order here: <I>main</I> won't
+be happy until it knows what a <I>Logging_Acceptor</I> is and the acceptor
+won't be happy until it knows what a <I>Logging_Handler</I> is. The next
+page pulls in this last definition for us and after that we tie it all
+together.</P>
+
+<P>
+<HR WIDTH="100%"></P>
+
+<CENTER><P>[<A HREF="../../Tutorial">Tutorial Index</A>] [<A HREF="page02.html">Previous
+Page</A>] [<A HREF="page04.html">Continue This Tutorial</A>] </P></CENTER>
+
+</BODY>
+</HTML>
diff --git a/docs/tutorials/002/page04.html b/docs/tutorials/002/page04.html
new file mode 100644
index 00000000000..9556ed6c96a
--- /dev/null
+++ b/docs/tutorials/002/page04.html
@@ -0,0 +1,265 @@
+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 3.2//EN">
+<HTML>
+<HEAD>
+ <TITLE>ACE Tutorial 002</TITLE>
+ <META NAME="GENERATOR" CONTENT="Mozilla/3.01Gold (Win95; I) [Netscape]">
+ <META NAME="Author" CONTENT="James CE Johnson">
+ <META NAME="Description" CONTENT="A first step towards using ACE productively">
+</HEAD>
+<BODY text = "#000000" link="#000fff" vlink="#ff0f0f" bgcolor="#ffffff">
+
+
+<CENTER><P><B><FONT SIZE=+2>ACE&nbsp;Tutorial 002<BR>
+Creating a Better Server </FONT></B></P></CENTER>
+
+<P>
+<HR WIDTH="100%"></P>
+
+<P>Since we've gone out of our way to make sure that the other parts of
+the program are generic, you may expect that this final piece, the connection
+handler, will be the most complicated. As usual, you are correct:</P>
+
+<UL>
+<PRE>1. #include &quot;ace/SOCK_Acceptor.h&quot;
+2. #include &quot;ace/Reactor.h&quot;
+
+
+3. class Logging_Handler : public ACE_Svc_Handler&lt;ACE_SOCK_STREAM, ACE_NULL_SYNCH&gt;
+ {
+
+ public:
+
+4. Logging_Handler (void)
+ {
+ }
+
+5. virtual void destroy (void)
+ {
+6. g_reactor-&gt;cancel_timer (this);
+7. this-&gt;peer ().close ();
+ }
+
+8. virtual int open (void *)
+ {
+9. ACE_INET_Addr addr;
+
+10. if (this-&gt;peer ().get_remote_addr (addr) == -1)
+11. return -1;
+12. else
+ {
+13. ACE_OS::strncpy (this-&gt;peer_name_, addr.get_host_name (), MAXHOSTNAMELEN + 1);
+
+14. if (g_reactor-&gt;register_handler(this, ACE_Event_Handler::READ_MASK) == -1)
+15. ACE_ERROR_RETURN ((LM_ERROR, &quot;(%P|%t) can't register with reactor\n&quot;), -1);
+
+16. else if (g_reactor-&gt;schedule_timer (this, (const void *) this, ACE_Time_Value (2), ACE_Time_Value (2)) == -1)
+17. ACE_ERROR_RETURN ((LM_ERROR, &quot;can'(%P|%t) t register with reactor\n&quot;), -1);
+
+18. else
+19. ACE_DEBUG ((LM_DEBUG, &quot;(%P|%t) connected with %s\n&quot;, this-&gt;peer_name_));
+
+20. return 0;
+ }
+ }
+
+21. virtual int close (u_long)
+ {
+22. this-&gt;destroy ();
+23. return 0;
+ }
+
+ protected:
+
+24. virtual int handle_input (ACE_HANDLE)
+ {
+25. char buf[128];
+26. memset(buf,0,sizeof(buf));
+
+27. switch( this-&gt;peer().recv(buf,sizeof buf) )
+ {
+28. case -1:
+29. ACE_ERROR_RETURN ((LM_ERROR, &quot;(%P|%t) %p bad read\n&quot;, &quot;client logger&quot;), -1);
+30. case 0:
+31. ACE_ERROR_RETURN ((LM_ERROR, &quot;(%P|%t) closing log daemon (fd = %d)\n&quot;, this-&gt;get_handle ()), -1);
+32. default:
+33. ACE_DEBUG ((LM_DEBUG, &quot;(%P|%t) from client: %s&quot;,buf));
+ }
+
+34. return 0;
+ }
+
+35. virtual int handle_timeout (const ACE_Time_Value &amp;tv, const void *arg)
+ {
+36. ACE_ASSERT (arg == this);
+37. ACE_DEBUG ((LM_DEBUG, &quot;(%P|%t) handling timeout from this = %u\n&quot;, this));
+38. return 0;
+ }
+
+ private:
+
+39. char peer_name_[MAXHOSTNAMELEN + 1];
+
+ };
+</PRE>
+</UL>
+
+<P>
+<HR WIDTH="100%"></P>
+
+<P>Here's the step-by-step explanation:</P>
+
+<OL>
+<LI>This has no business being here but I refuse to renumber 38 lines of
+source just to get rid of it.</LI>
+
+<LI>Come to think of it, this is probably not needed either. While we use
+the global reactor object (<I>g_reactor</I>) througout this portion of
+code, we don't actually create any new ones. Besides, we'll drop this code
+into one file with <I>main</I> and <I>acceptor</I> and it won't matter.</LI>
+
+<LI>We've apparently decided to be bold and use yet another ACE template
+to create our <I>Logging_Handler</I> object. From the manual, the <I>ACE_Svc_Handler</I>
+template <I>defines the interface for a service that exchanges data with
+its connected peer</I>. The first template argument specifies the kind
+of connection we want to have. As mentioned on the previous page, this
+<B>must</B> be compatible with the data type used to accept the connection.
+As for the second argument, I have no idea. Somebody please explain this
+to me.</LI>
+
+<LI>Our default constructor does nothing. We've moved anything with failure
+potential into the <I>open</I> function. Should the constructor be virtual?</LI>
+
+<LI>This should be called instead of <I>delete</I>. It will shut down the
+object gracefully. I don't fully understand...</LI>
+
+<LI>Cancel any timer(s) which the reactor associates with this object</LI>
+
+<LI>Close the connection to the client. Notice that we use the <I>peer()</I>
+member function generated by the template. We should never need direct
+access to the actual connection object.</LI>
+
+<LI>The <I>open</I> function contains all of our initialization logic.
+It is called by the acceptor when a new connection is accepted. If we fail
+to initialize for any reason, we will return an error code so that the
+acceptor can respond correctly. This could not be done in a constructor.</LI>
+
+<LI>Create a temporary variable that will hold the address of the client
+system.</LI>
+
+<LI>Ask the connection object to give us the address of the client system.
+This is something you will usually want to do for logging or validation
+purposes whenever a new connection is received. See how easy it is?</LI>
+
+<LI>Tell the acceptor if we could not get the peer's address. Shouldn't
+we have used <I>ACE_ERROR_RETURN</I>? You tell me.</LI>
+
+<LI>But, if the peer's address was gotten...</LI>
+
+<LI>Copy the peer's host name into a member variable. We could have simply
+stored the address object but that has more information than we want to
+keep around for a long time. Notice how the <I>ACE_OS</I> class is used
+to access expected &quot;normal&quot; functions. While that may be a bit
+of overkill, it does give us another level of abstraction from one platform
+to another.</LI>
+
+<LI>As usual, we ultimately register ourselves with a reactor. Since we're
+only interested in responding to the client's data, we only ask for <I>READ</I>
+events to be sent to us.</LI>
+
+<LI>Another possible failure point...</LI>
+
+<LI>Just for giggles, we've decided to register a timer event with the
+reactor also. As shown here, it will delay two seconds before firing the
+first timer event and then be rescheduled every two seconds after that.
+Timer resolutions of milliseconds can be used too!</LI>
+
+<LI>But, of course, any registration may fail.</LI>
+
+<LI>Everything must have worked if we got here</LI>
+
+<LI>so tell the driver about it</LI>
+
+<LI>and return success to the acceptor which invoked us.</LI>
+
+<LI>When we're asked to close ourselves, we first destroy the timer and
+peer connection. It seems to me that we should do a <I>delete this</I>
+at some point. Perhaps <I>destroy</I> should do that?</LI>
+
+<LI>Invoke the destroy method to clean everything up</LI>
+
+<LI>and return a success status.</LI>
+
+<LI><I>handle_input</I> is where you do whatever your application requires
+when data is received from the client system.</LI>
+
+<LI>Create a storage space for the received data</LI>
+
+<LI>and make sure it is empty.</LI>
+
+<LI>Receive as much data as we can but don't overrun our buffer. For this
+simple example, we don't get too fancy. In a real application we would
+probably read some number of bytes (4?) and create a number from them.
+We would then use that number to decide how many more bytes to read. The
+number could be a simple byte count or it could be a packet type indicator
+which implies a bytecount.</LI>
+
+<LI>If <I>recv</I> returns <I>-1</I> then there is something bad wrong
+with the connection so</LI>
+
+<LI>we return an <I>-1</I> to the reactor along with a failure message.
+We cannot continue after this.</LI>
+
+<LI>A <I>0</I> return from <I>recv</I> is not quite so bad. However, <I>handle_input</I>
+wouldn't have been called if there was no data to be read. So, we take
+this to be a sign that the client chose to shutdown the connection.</LI>
+<LI>Like the case above, we need to return a <I>-1</I> to the reactor
+so that we can be shutdown. </LI>
+
+<LI>Any other value from <I>recv</I> is taken to indicate the number of
+bytes received so</LI>
+
+<LI>we display the data to the user. In the real world, we could do an
+infinite number of things with the data.</LI>
+
+<LI>Return <I>0</I> if all is well with the receive so that the reactor
+will allow us to continue functioning.</LI>
+
+<LI><I>handle_timeout</I> is something we haven't seen in any example so
+far. Like <I>handle_input</I>, it is called by the reactor based on an
+event. In this case, the event will be expiration of the timer we set in
+the <I>open</I> function.</LI>
+
+<LI>It seems kind of silly for the handler to get a pointer to <I>this</I>
+when the other handlers don't. Still, when given information of this type,
+it is generally good to check it.</LI>
+
+<LI>Display a simple message to tell the user that we got the timer. In
+your program, you may be expecting periodic data from your client. Simply
+set a timer whenver you are through receiving data and cancel it whenever
+you begin receiving it. If the timer handler is ever called, then you know
+you didn't get data within the time you wanted.</LI>
+
+<LI>Returning <I>0</I> will tell the reactor to reschedule the timer as
+configured in the <I>open</I> function.</LI>
+
+<LI>A simple string to hold the name of the client system. We could have
+kept the entire <I>ACE_INET_Addr</I> object but we really only wanted the
+name &amp; not the extra baggage.</LI>
+</OL>
+
+<P>Obviously this is a bit more complicated than the rest of the program.
+Still, you see there isn't a lot of networking knowlege needed to get this
+up and going. There are unfortunately several questions that I can't answer
+(such as the <I>delete this</I> issue) but given time, I'm sure we'll all
+figure it out.</P>
+
+<P>
+<HR WIDTH="100%"></P>
+
+<CENTER><P>[<A HREF="..">Tutorial
+Index</A>] [<A HREF="page03.html">Previous
+Page</A>] [<A HREF="page05.html">Continue
+This Tutorial</A>] </P></CENTER>
+
+</BODY>
+</HTML>
diff --git a/docs/tutorials/002/page05.html b/docs/tutorials/002/page05.html
new file mode 100644
index 00000000000..02a6432f45c
--- /dev/null
+++ b/docs/tutorials/002/page05.html
@@ -0,0 +1,41 @@
+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 3.2//EN">
+<HTML>
+<HEAD>
+ <TITLE>ACE Tutorial 002</TITLE>
+ <META NAME="GENERATOR" CONTENT="Mozilla/3.01Gold (Win95; I) [Netscape]">
+ <META NAME="Author" CONTENT="James CE Johnson">
+ <META NAME="Description" CONTENT="A first step towards using ACE productively">
+</HEAD>
+<BODY text = "#000000" link="#000fff" vlink="#ff0f0f" bgcolor="#ffffff">
+
+
+<CENTER><P><B><FONT SIZE=+2>ACE&nbsp;Tutorial 002<BR>
+Creating a Better Server </FONT></B></P></CENTER>
+
+<P>
+<HR WIDTH="100%"></P>
+
+<P>Well, that's it for the second tutorial. We've found a much easier way
+to create a server, especially the acceptor part. At the same time, we
+introduced more functionality and robustness. Not bad for a day's work.</P>
+
+<P>As promised, this all fits together into a single file that is just
+over 120 lines long:</P>
+
+<UL>
+<LI><A HREF="00SetEnv">Environment Settings</A></LI>
+
+<LI><A HREF="Makefile">Makefile</A></LI>
+
+<LI><A HREF="server.cpp">server.cpp</A></LI>
+</UL>
+
+<P>
+<HR WIDTH="100%"></P>
+
+<CENTER><P>[<A HREF="..">Tutorial
+Index</A>] [<A HREF="page03.html">Previous
+Page</A>]</P></CENTER>
+
+</BODY>
+</HTML>
diff --git a/docs/tutorials/002/server b/docs/tutorials/002/server
new file mode 100644
index 00000000000..9692758dcf4
--- /dev/null
+++ b/docs/tutorials/002/server
Binary files differ
diff --git a/docs/tutorials/002/server.cpp b/docs/tutorials/002/server.cpp
new file mode 100644
index 00000000000..d011da87476
--- /dev/null
+++ b/docs/tutorials/002/server.cpp
@@ -0,0 +1,124 @@
+// $Id$
+
+#include "ace/Acceptor.h"
+#include "ace/SOCK_Acceptor.h"
+#include "ace/Reactor.h"
+
+ACE_Reactor * g_reactor;
+
+static sig_atomic_t finished = 0;
+extern "C" void handler (int) { finished = 1; }
+
+// ----------------------------------------
+
+class Logging_Handler : public ACE_Svc_Handler<ACE_SOCK_STREAM, ACE_NULL_SYNCH>
+{
+
+public:
+
+ Logging_Handler (void)
+ {
+ }
+
+ virtual void destroy (void)
+ {
+ g_reactor->cancel_timer (this);
+ this->peer ().close ();
+ delete this;
+ }
+
+ virtual int open (void *)
+ {
+ ACE_INET_Addr addr;
+
+ if (this->peer ().get_remote_addr (addr) == -1)
+ return -1;
+ else
+ {
+ ACE_OS::strncpy (this->peer_name_, addr.get_host_name (), MAXHOSTNAMELEN + 1);
+
+ if (g_reactor->register_handler(this, ACE_Event_Handler::READ_MASK) == -1)
+ ACE_ERROR_RETURN ((LM_ERROR, "(%P|%t) can't register with reactor\n"), -1);
+
+ else if (g_reactor->schedule_timer (this, (const void *) this, ACE_Time_Value (2), ACE_Time_Value (2)) == -1)
+ ACE_ERROR_RETURN ((LM_ERROR, "can'(%P|%t) t register with reactor\n"), -1);
+
+ else
+ ACE_DEBUG ((LM_DEBUG, "(%P|%t) connected with %s\n", this->peer_name_));
+
+ return 0;
+ }
+ }
+
+ virtual int close (u_long)
+ {
+ this->destroy ();
+ return 0;
+ }
+
+protected:
+
+ virtual int handle_input (ACE_HANDLE)
+ {
+ char buf[128];
+ memset(buf,0,sizeof(buf));
+
+ switch( this->peer().recv(buf,sizeof buf) )
+ {
+ case -1:
+ ACE_ERROR_RETURN ((LM_ERROR, "(%P|%t) %p bad read\n", "client logger"), -1);
+ case 0:
+ ACE_ERROR_RETURN ((LM_ERROR, "(%P|%t) closing log daemon (fd = %d)\n", this->get_handle ()), -1);
+ default:
+ ACE_DEBUG ((LM_DEBUG, "(%P|%t) from client: %s",buf));
+ }
+
+ return 0;
+ }
+
+ virtual int handle_timeout (const ACE_Time_Value &tv, const void *arg)
+ {
+ ACE_ASSERT (arg == this);
+ ACE_DEBUG ((LM_DEBUG, "(%P|%t) handling timeout from this = %u\n", this));
+ return 0;
+ }
+
+private:
+
+ char peer_name_[MAXHOSTNAMELEN + 1];
+
+};
+
+
+typedef ACE_Acceptor <Logging_Handler, ACE_SOCK_ACCEPTOR> Logging_Acceptor;
+
+
+static const u_short PORT = ACE_DEFAULT_SERVER_PORT;
+
+int main (int argc, char *argv[])
+{
+ g_reactor = new ACE_Reactor;
+
+ // Acceptor factory.
+ Logging_Acceptor peer_acceptor;
+
+ if (peer_acceptor.open (ACE_INET_Addr (PORT)) == -1)
+ ACE_ERROR_RETURN ((LM_ERROR, "%p\n", "open"), -1);
+
+ else if (g_reactor->register_handler (&peer_acceptor, ACE_Event_Handler::READ_MASK) == -1)
+ ACE_ERROR_RETURN ((LM_ERROR, "registering service with ACE_Reactor\n"), -1);
+
+ ACE_Sig_Action sa ((ACE_SignalHandler) handler, SIGINT);
+
+ // Run forever, performing logging service.
+
+ ACE_DEBUG ((LM_DEBUG, "(%P|%t) starting up server logging daemon\n"));
+
+ // Perform logging service until QUIT_HANDLER receives SIGINT.
+ while ( !finished )
+ g_reactor->handle_events ();
+
+ ACE_DEBUG ((LM_DEBUG, "(%P|%t) shutting down server logging daemon\n"));
+
+ return 0;
+}
diff --git a/docs/tutorials/003/00SetEnv b/docs/tutorials/003/00SetEnv
new file mode 100644
index 00000000000..33ba8135007
--- /dev/null
+++ b/docs/tutorials/003/00SetEnv
@@ -0,0 +1,2 @@
+export WRAPPER_ROOT=/local/src/ACE/ACE_wrappers
+export LD_LIBRARY_PATH=$WRAPPER_ROOT/ace:$LD_LIBRARY_PATH
diff --git a/docs/tutorials/003/Makefile b/docs/tutorials/003/Makefile
new file mode 100644
index 00000000000..cb94a47f960
--- /dev/null
+++ b/docs/tutorials/003/Makefile
@@ -0,0 +1,66 @@
+#----------------------------------------------------------------------------
+# $Id$
+#
+# Makefile for client logging applications
+#----------------------------------------------------------------------------
+
+#----------------------------------------------------------------------------
+# Local macros
+#----------------------------------------------------------------------------
+
+BIN = client
+
+LSRC = $(addsuffix .cpp,$(BIN))
+
+VLDLIBS = $(LDLIBS:%=%$(VAR))
+
+BUILD = $(VBIN)
+
+#----------------------------------------------------------------------------
+# Include macros and targets
+#----------------------------------------------------------------------------
+
+include $(WRAPPER_ROOT)/include/makeinclude/wrapper_macros.GNU
+include $(WRAPPER_ROOT)/include/makeinclude/macros.GNU
+include $(WRAPPER_ROOT)/include/makeinclude/rules.common.GNU
+include $(WRAPPER_ROOT)/include/makeinclude/rules.nonested.GNU
+include $(WRAPPER_ROOT)/include/makeinclude/rules.bin.GNU
+include $(WRAPPER_ROOT)/include/makeinclude/rules.local.GNU
+
+#----------------------------------------------------------------------------
+# Local targets
+#----------------------------------------------------------------------------
+
+#----------------------------------------------------------------------------
+# Dependencies
+#----------------------------------------------------------------------------
+
+# DO NOT DELETE THIS LINE -- g++dep uses it.
+# DO NOT PUT ANYTHING AFTER THIS LINE, IT WILL GO AWAY.
+
+.obj/client.o .shobj/client.so: client.cpp \
+ $(WRAPPER_ROOT)/ace/SOCK_Connector.h \
+ $(WRAPPER_ROOT)/ace/SOCK_Stream.h \
+ $(WRAPPER_ROOT)/ace/SOCK_IO.h \
+ $(WRAPPER_ROOT)/ace/SOCK.h \
+ $(WRAPPER_ROOT)/ace/ACE.h \
+ $(WRAPPER_ROOT)/ace/OS.h \
+ $(WRAPPER_ROOT)/ace/Time_Value.h \
+ $(WRAPPER_ROOT)/ace/config.h \
+ $(WRAPPER_ROOT)/ace/stdcpp.h \
+ $(WRAPPER_ROOT)/ace/Trace.h \
+ $(WRAPPER_ROOT)/ace/Log_Msg.h \
+ $(WRAPPER_ROOT)/ace/Log_Record.h \
+ $(WRAPPER_ROOT)/ace/Log_Priority.h \
+ $(WRAPPER_ROOT)/ace/Log_Record.i \
+ $(WRAPPER_ROOT)/ace/ACE.i \
+ $(WRAPPER_ROOT)/ace/Addr.h \
+ $(WRAPPER_ROOT)/ace/IPC_SAP.h \
+ $(WRAPPER_ROOT)/ace/IPC_SAP.i \
+ $(WRAPPER_ROOT)/ace/SOCK.i \
+ $(WRAPPER_ROOT)/ace/SOCK_IO.i \
+ $(WRAPPER_ROOT)/ace/INET_Addr.h \
+ $(WRAPPER_ROOT)/ace/SOCK_Stream.i \
+ $(WRAPPER_ROOT)/ace/SOCK_Connector.i
+
+# IF YOU PUT ANYTHING HERE IT WILL GO AWAY
diff --git a/docs/tutorials/003/client b/docs/tutorials/003/client
new file mode 100644
index 00000000000..90af3ef942c
--- /dev/null
+++ b/docs/tutorials/003/client
Binary files differ
diff --git a/docs/tutorials/003/client.cpp b/docs/tutorials/003/client.cpp
new file mode 100644
index 00000000000..a420a69e936
--- /dev/null
+++ b/docs/tutorials/003/client.cpp
@@ -0,0 +1,38 @@
+// $Id$
+
+#include "ace/SOCK_Connector.h"
+
+static u_short SERVER_PORT = ACE_DEFAULT_SERVER_PORT;
+static const char *const SERVER_HOST = ACE_DEFAULT_SERVER_HOST;
+static const int MAX_ITERATIONS = 4;
+
+int main (int argc, char *argv[])
+{
+ const char *server_host = argc > 1 ? argv[1] : SERVER_HOST;
+ u_short server_port = argc > 2 ? ACE_OS::atoi (argv[2]) : SERVER_PORT;
+ int max_iterations = argc > 3 ? ACE_OS::atoi (argv[3]) : MAX_ITERATIONS;
+
+ ACE_SOCK_Stream server;
+ ACE_SOCK_Connector connector;
+ ACE_INET_Addr addr (server_port, server_host);
+
+ if (connector.connect (server, addr) == -1)
+ ACE_ERROR_RETURN ((LM_ERROR, "%p\n", "open"), -1);
+
+ for (int i = 0; i < max_iterations; i++)
+ {
+ char buf[BUFSIZ];
+
+ ::sprintf (buf, "message = %d\n", i + 1);
+
+ if (server.send_n ( buf, strlen(buf) ) == -1)
+ ACE_ERROR_RETURN ((LM_ERROR, "%p\n", "send"), -1);
+ else
+ ACE_OS::sleep (1);
+ }
+
+ if (server.close () == -1)
+ ACE_ERROR_RETURN ((LM_ERROR, "%p\n", "close"), -1);
+
+ return 0;
+}
diff --git a/docs/tutorials/003/page01.html b/docs/tutorials/003/page01.html
new file mode 100644
index 00000000000..ec1f5a311cf
--- /dev/null
+++ b/docs/tutorials/003/page01.html
@@ -0,0 +1,168 @@
+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 3.2//EN">
+<HTML>
+<HEAD>
+ <TITLE>ACE Tutorial 003</TITLE>
+ <META NAME="GENERATOR" CONTENT="Mozilla/3.01Gold (Win95; I) [Netscape]">
+ <META NAME="Author" CONTENT="James CE Johnson">
+ <META NAME="Description" CONTENT="A first step towards using ACE productively">
+</HEAD>
+<BODY text = "#000000" link="#000fff" vlink="#ff0f0f" bgcolor="#ffffff">
+
+
+<CENTER><P><B><FONT SIZE=+2>ACE&nbsp;Tutorial 003<BR>
+Creating a Simple Client</FONT></B></P></CENTER>
+
+<P>
+<HR WIDTH="100%"></P>
+
+<P>Now that we've seen how to create servers, let's spend just a moment
+making a client. Since this is so easy, I'm going to do all of it in this
+one page.</P>
+
+<P>
+<HR WIDTH="100%"></P>
+
+<P>First, a look at the code:</P>
+
+<UL>
+<PRE>
+1. #include &quot;ace/SOCK_Connector.h&quot;
+
+2. static u_short SERVER_PORT = ACE_DEFAULT_SERVER_PORT;
+3. static const char *const SERVER_HOST = ACE_DEFAULT_SERVER_HOST;
+4. static const int MAX_ITERATIONS = 4;
+
+5. int main (int argc, char *argv[])
+ {
+6. const char *server_host = argc &gt; 1 ? argv[1] : SERVER_HOST;
+7. u_short server_port = argc &gt; 2 ? ACE_OS::atoi (argv[2]) : SERVER_PORT;
+8. int max_iterations = argc &gt; 3 ? ACE_OS::atoi (argv[3]) : MAX_ITERATIONS;
+
+9. ACE_SOCK_Stream server;
+10. ACE_SOCK_Connector connector;
+11. ACE_INET_Addr addr (server_port, server_host);
+
+12. if (connector.connect (server, addr) == -1)
+ {
+13. ACE_ERROR_RETURN ((LM_ERROR, &quot;%p\n&quot;, &quot;open&quot;), -1);
+ }
+
+14. for (int i = 0; i &lt; max_iterations; i++)
+ {
+15. char buf[BUFSIZ];
+
+16. ::sprintf (buf, &quot;message = %d\n&quot;, i + 1);
+
+17. if (server.send_n ( buf, strlen(buf) ) == -1)
+ {
+18. ACE_ERROR_RETURN ((LM_ERROR, &quot;%p\n&quot;, &quot;send&quot;), -1);
+ }
+19. else
+ {
+20. ACE_OS::sleep (1);
+ }
+ }
+
+21. if (server.close () == -1)
+ {
+22. ACE_ERROR_RETURN ((LM_ERROR, &quot;%p\n&quot;, &quot;close&quot;), -1);
+ }
+
+23. return 0;
+ }
+</PRE>
+</UL>
+
+<P>
+<HR WIDTH="100%"></P>
+
+<P>Now, the code description:</P>
+
+<OL>
+<LI>Include the ACE socket objects. We'll need this in a minute when we
+establish the connection.</LI>
+
+<LI>For simplicity, we define a default TCP/IP&nbsp;port,</LI>
+
+<LI>and server name. We allow command-line override but in reality this
+might be quite a bit more complicated.</LI>
+
+<LI>A default iterations count is also defined.</LI>
+
+<LI>Good ol' <I>main</I> will be our one and only function.</LI>
+
+<LI>Set the server hostname, allowing command-line override.</LI>
+
+<LI>Set the server's TCP/IP port</LI>
+
+<LI>and the iteration count similarly.</LI>
+
+<LI>Build ourselves a Stream socket. This is a connected socket that provides
+reliable end-to-end communications. We will use the <I>server</I> object
+to send data to the server we connect to.</LI>
+
+<LI>And we need a <I>connector</I> object to establish that connection.
+The <I>ACE_SOCK_Connector</I> object provides all of the tools we need
+to establish a connection once we know the server's network address...</LI>
+
+<LI>Which we create with an <I>ACE_INET_Addr</I> object. This object is
+given the TCP/IP port and hostname of the server we want to connect to.
+It creates a generic address object for us to use in connection attempts.</LI>
+
+<LI>So, we feed the <I>Addr</I> object and the <I>Stream</I> object to
+the <I>connector</I>'s <I>connect</I> member function. Given this information,
+it will establish the network connection to the server and attacht that
+connection to the <I>server</I> object.</LI>
+
+<LI>If we fail, we will exit semi-gracefully.</LI>
+
+<LI>For this simple example, we use a <I>for</I> loop do send messages
+to the server.</LI>
+
+<LI>We use this buffer to build the message</LI>
+
+<LI>using the <I>sprintf</I> command and some useless data.</LI>
+
+<LI>Once the data is available, we use the <I>server</I> object's <I>send_n</I>
+function to send all of the data at once. There is also a <I>send</I> function
+but it may not send all of the data. That is due to network buffer availability
+and such. If the <I>send</I> doesn't send all of the data, it is up to
+you to program things such that it will keep trying until all of the data
+is sent or simply give up. The <I>send_n</I> function already does the
+&quot;keep tyring&quot; option for us, so we use it.</LI>
+
+<LI>Since <I>send_n</I> is so reliable, we may as well give up when it
+fails.</LI>
+
+<LI>But if it doesn't fail</LI>
+
+<LI>kick back and snooze for a second.</LI>
+
+<LI>Attempt to close the connection to the server. </LI>
+
+<LI>If it fails, we display a simple message. If enough of these fail,
+though, we may run out of network resources. It is a good idea to fix any
+failure if at all possible.</LI>
+
+<LI>All done.</LI>
+</OL>
+
+<P>
+<HR WIDTH="100%"></P>
+
+<P>Ok, so that was pretty easy. What would be even easier would be to wrap
+all of the connection mess up in an object and overload a couple of basic
+operators to make things less network-centric. Perhaps we'll see that in
+another tutorial.</P>
+
+<P>
+If you want to compile it yourself, here's the <A HREF="client.cpp">source</A>,
+the <A HREF="Makefile">Makefile</A>, and <A HREF="00SetEnv">Environment settings</A>.
+<P>
+<HR WIDTH="100%"></P>
+
+<CENTER><P>[<A HREF="..">Tutorial
+Index</A>]</P></CENTER>
+
+</BODY>
+</HTML>
diff --git a/docs/tutorials/004/00SetEnv b/docs/tutorials/004/00SetEnv
new file mode 100644
index 00000000000..33ba8135007
--- /dev/null
+++ b/docs/tutorials/004/00SetEnv
@@ -0,0 +1,2 @@
+export WRAPPER_ROOT=/local/src/ACE/ACE_wrappers
+export LD_LIBRARY_PATH=$WRAPPER_ROOT/ace:$LD_LIBRARY_PATH
diff --git a/docs/tutorials/004/Makefile b/docs/tutorials/004/Makefile
new file mode 100644
index 00000000000..5c5f03dc063
--- /dev/null
+++ b/docs/tutorials/004/Makefile
@@ -0,0 +1,68 @@
+#----------------------------------------------------------------------------
+# $Id$
+#
+# Makefile for client logging applications
+#----------------------------------------------------------------------------
+
+#----------------------------------------------------------------------------
+# Local macros
+#----------------------------------------------------------------------------
+
+BIN = client
+
+LSRC = $(addsuffix .cpp,$(BIN))
+
+VLDLIBS = $(LDLIBS:%=%$(VAR))
+
+BUILD = $(VBIN)
+
+CFLAGS = -fhandle-exceptions
+
+#----------------------------------------------------------------------------
+# Include macros and targets
+#----------------------------------------------------------------------------
+
+include $(WRAPPER_ROOT)/include/makeinclude/wrapper_macros.GNU
+include $(WRAPPER_ROOT)/include/makeinclude/macros.GNU
+include $(WRAPPER_ROOT)/include/makeinclude/rules.common.GNU
+include $(WRAPPER_ROOT)/include/makeinclude/rules.nonested.GNU
+include $(WRAPPER_ROOT)/include/makeinclude/rules.bin.GNU
+include $(WRAPPER_ROOT)/include/makeinclude/rules.local.GNU
+
+#----------------------------------------------------------------------------
+# Local targets
+#----------------------------------------------------------------------------
+
+#----------------------------------------------------------------------------
+# Dependencies
+#----------------------------------------------------------------------------
+
+# DO NOT DELETE THIS LINE -- g++dep uses it.
+# DO NOT PUT ANYTHING AFTER THIS LINE, IT WILL GO AWAY.
+
+.obj/client.o .shobj/client.so: client.cpp \
+ $(WRAPPER_ROOT)/ace/SOCK_Connector.h \
+ $(WRAPPER_ROOT)/ace/SOCK_Stream.h \
+ $(WRAPPER_ROOT)/ace/SOCK_IO.h \
+ $(WRAPPER_ROOT)/ace/SOCK.h \
+ $(WRAPPER_ROOT)/ace/ACE.h \
+ $(WRAPPER_ROOT)/ace/OS.h \
+ $(WRAPPER_ROOT)/ace/Time_Value.h \
+ $(WRAPPER_ROOT)/ace/config.h \
+ $(WRAPPER_ROOT)/ace/stdcpp.h \
+ $(WRAPPER_ROOT)/ace/Trace.h \
+ $(WRAPPER_ROOT)/ace/Log_Msg.h \
+ $(WRAPPER_ROOT)/ace/Log_Record.h \
+ $(WRAPPER_ROOT)/ace/Log_Priority.h \
+ $(WRAPPER_ROOT)/ace/Log_Record.i \
+ $(WRAPPER_ROOT)/ace/ACE.i \
+ $(WRAPPER_ROOT)/ace/Addr.h \
+ $(WRAPPER_ROOT)/ace/IPC_SAP.h \
+ $(WRAPPER_ROOT)/ace/IPC_SAP.i \
+ $(WRAPPER_ROOT)/ace/SOCK.i \
+ $(WRAPPER_ROOT)/ace/SOCK_IO.i \
+ $(WRAPPER_ROOT)/ace/INET_Addr.h \
+ $(WRAPPER_ROOT)/ace/SOCK_Stream.i \
+ $(WRAPPER_ROOT)/ace/SOCK_Connector.i
+
+# IF YOU PUT ANYTHING HERE IT WILL GO AWAY
diff --git a/docs/tutorials/004/client b/docs/tutorials/004/client
new file mode 100644
index 00000000000..75c5a1d3690
--- /dev/null
+++ b/docs/tutorials/004/client
Binary files differ
diff --git a/docs/tutorials/004/client.cpp b/docs/tutorials/004/client.cpp
new file mode 100644
index 00000000000..295d8131f8f
--- /dev/null
+++ b/docs/tutorials/004/client.cpp
@@ -0,0 +1,141 @@
+// $Id$
+
+#include "ace/SOCK_Connector.h"
+#include "ace/SString.h"
+
+class Client : private ACE_SOCK_Stream
+{
+public:
+ ACE_SOCK_Stream::close; // promote to public
+
+ Client(void);
+ Client( const char * server, u_short port );
+
+ int open( const char * server, u_short port );
+
+ inline int initialized(void) { return mInitialized; }
+ inline int error(void) { return mError; }
+
+ Client & operator<<( ACE_SString & str );
+ Client & operator<<( char * str );
+ Client & operator<<( int n );
+
+ class Error {};
+
+protected:
+
+private:
+ unsigned char mInitialized;
+ unsigned char mError;
+};
+
+Client::Client(void)
+{
+ mInitialized = 0;
+ mError = 0;
+}
+
+Client::Client( const char * server, u_short port )
+{
+ mInitialized = 0;
+ mError = 0;
+ (void)open(server,port);
+}
+
+int Client::open( const char * server, u_short port )
+{
+ ACE_SOCK_Connector connector;
+ ACE_INET_Addr addr (port, server);
+
+ if (connector.connect (*this, addr) == -1)
+ {
+ ACE_ERROR_RETURN ((LM_ERROR, "%p\n", "open"), -1);
+ }
+
+ mInitialized = 1;
+
+ return(0);
+}
+
+Client & Client::operator<<( ACE_SString & str )
+{
+ if( initialized() )
+ {
+ if( error() )
+ {
+ throw Error();
+ }
+
+ char * cp = str.rep();
+
+ mError = 0;
+
+ if( this->send_n(cp,strlen(cp)) == -1 )
+ {
+ mError = 1;
+ throw Error();
+ }
+ }
+ else
+ {
+ mError = 2;
+ throw Error();
+ }
+
+ return *this ;
+}
+
+Client & Client::operator<< ( char * str )
+{
+ ACE_SString newStr(str);
+
+ *this << newStr;
+
+ return *this ;
+}
+
+Client & Client::operator<< ( int n )
+{
+ char buf[1024];
+ sprintf(buf,"(%d)\n",n);
+ ACE_SString newStr(buf);
+
+ *this << newStr;
+
+ return *this;
+}
+
+int main (int argc, char *argv[])
+{
+ const char *server_host = argc > 1 ? argv[1] : ACE_DEFAULT_SERVER_HOST;
+ u_short server_port = argc > 2 ? ACE_OS::atoi (argv[2]) : ACE_DEFAULT_SERVER_PORT;
+ int max_iterations = argc > 3 ? ACE_OS::atoi (argv[3]) : 4;
+
+ Client server(server_host,server_port);
+
+ if( ! server.initialized() )
+ {
+ ACE_ERROR_RETURN ((LM_ERROR, "%p\n", "intialization"), -1);
+ }
+
+
+ for (int i = 0; i < max_iterations; i++)
+ {
+ try
+ {
+ server << "message = " << i+1;
+ ACE_OS::sleep (1);
+ }
+ catch ( Client::Error & e )
+ {
+ cout << "There was an error sending the data\n";
+ }
+ }
+
+ if (server.close () == -1)
+ {
+ ACE_ERROR_RETURN ((LM_ERROR, "%p\n", "close"), -1);
+ }
+
+ return 0;
+}
diff --git a/docs/tutorials/004/foo b/docs/tutorials/004/foo
new file mode 100644
index 00000000000..ed5e75c78da
--- /dev/null
+++ b/docs/tutorials/004/foo
@@ -0,0 +1,141 @@
+
+1. #include "ace/SOCK_Connector.h"
+2. #include "ace/SString.h"
+
+3. class Client : private ACE_SOCK_Stream
+ {
+
+ public:
+4. ACE_SOCK_Stream::close; // promote to public
+
+5. Client(void);
+6. Client( const char * server, u_short port );
+
+7. int open( const char * server, u_short port );
+
+8. inline int initialized(void) { return mInitialized; }
+9. inline int error(void) { return mError; }
+
+10. Client & operator<<( ACE_SString & str );
+11. Client & operator<<( char * str );
+12. Client & operator<<( int n );
+
+13. class Error {};
+
+ protected:
+
+ private:
+14. unsigned char mInitialized;
+15. unsigned char mError;
+ };
+
+16. Client::Client(void)
+ {
+17. mInitialized = 0;
+18. mError = 0;
+ }
+
+19. Client::Client( const char * server, u_short port )
+ {
+20. mInitialized = 0;
+21. mError = 0;
+22. (void)open(server,port);
+ }
+
+23. int Client::open( const char * server, u_short port )
+ {
+24. ACE_SOCK_Connector connector;
+25. ACE_INET_Addr addr (port, server);
+
+26. if (connector.connect (*this, addr) == -1)
+ {
+27. ACE_ERROR_RETURN ((LM_ERROR, "%p\n", "open"), -1);
+ }
+
+28. mInitialized = 1;
+
+29. return(0);
+ }
+
+30. Client & Client::operator<<( ACE_SString & str )
+ {
+31. if( initialized() )
+ {
+32. if( error() )
+ {
+33. throw Error();
+ }
+
+34. char * cp = str.rep();
+
+35. mError = 0;
+
+36. if( this->send_n(cp,strlen(cp)) == -1 )
+ {
+37. mError = 1;
+38. throw Error();
+ }
+ }
+39. else
+ {
+40. mError = 2;
+41. throw Error();
+ }
+
+42. return *this ;
+ }
+
+43. Client & Client::operator<< ( char * str )
+ {
+44. ACE_SString newStr(str);
+
+45. *this << newStr;
+
+46. return *this ;
+ }
+
+47. Client & Client::operator<< ( int n )
+ {
+48. char buf[1024];
+49. sprintf(buf,"(%d)\n",n);
+50. ACE_SString newStr(buf);
+
+51. *this << newStr;
+
+52. return *this;
+ }
+
+53. int main (int argc, char *argv[])
+ {
+54. const char *server_host = argc > 1 ? argv[1] : ACE_DEFAULT_SERVER_HOST;
+55. u_short server_port = argc > 2 ? ACE_OS::atoi (argv[2]) : ACE_DEFAULT_SERVER_PORT;
+56. int max_iterations = argc > 3 ? ACE_OS::atoi (argv[3]) : 4;
+
+57. Client server(server_host,server_port);
+
+58. if( ! server.initialized() )
+ {
+59. ACE_ERROR_RETURN ((LM_ERROR, "%p\n", "intialization"), -1);
+ }
+
+
+60. for (int i = 0; i < max_iterations; i++)
+ {
+61. try
+ {
+62. server << "message = " << i+1;
+63. ACE_OS::sleep (1);
+ }
+64. catch ( Client::Error & e )
+ {
+65. cout << "There was an error sending the data\n";
+ }
+ }
+
+66. if (server.close () == -1)
+ {
+67. ACE_ERROR_RETURN ((LM_ERROR, "%p\n", "close"), -1);
+ }
+
+68. return 0;
+ }
diff --git a/docs/tutorials/004/page01.html b/docs/tutorials/004/page01.html
new file mode 100644
index 00000000000..9d67730b0f8
--- /dev/null
+++ b/docs/tutorials/004/page01.html
@@ -0,0 +1,184 @@
+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 3.2//EN">
+<HTML>
+<HEAD>
+ <TITLE>ACE Tutorial 004</TITLE>
+ <META NAME="GENERATOR" CONTENT="Mozilla/3.01Gold (Win95; I) [Netscape]">
+ <META NAME="Author" CONTENT="James CE Johnson">
+ <META NAME="Description" CONTENT="A first step towards using ACE productively">
+</HEAD>
+<BODY text = "#000000" link="#000fff" vlink="#ff0f0f" bgcolor="#ffffff">
+
+
+<CENTER><P><B><FONT SIZE=+2>ACE&nbsp;Tutorial 004<BR>
+A much more clever Client</FONT></B></P></CENTER>
+
+<P>
+<HR WIDTH="100%"></P>
+
+<P>
+<HR WIDTH="100%"></P>
+
+<P>The code:</P>
+
+<UL>
+<PRE>
+1. #include &quot;ace/SOCK_Connector.h&quot;
+2. #include &quot;ace/SString.h&quot;
+
+3. class Client : public ACE_SOCK_Stream
+ {
+
+ public:
+4. Client(void);
+5. Client( const char * server, u_short port );
+
+6. int open( const char * server, u_short port );
+
+7. inline int initialized(void) { return mInitialized; }
+8. inline int error(void) { return mError; }
+
+9. Client operator&lt;&lt;( ACE_SString &amp; str );
+10. Client operator&lt;&lt;( char * str );
+11. Client operator&lt;&lt;( int n );
+
+ protected:
+
+ private:
+12. unsigned char mInitialized;
+13. unsigned char mError;
+
+ };
+
+14. Client::Client(void)
+ {
+15. mInitialized = 0;
+16. mError = 0;
+ }
+
+17. Client::Client( const char * server, u_short port )
+ {
+18. mInitialized = 0;
+19. mError = 0;
+20. (void)open(server,port);
+ }
+
+21. int Client::open( const char * server, u_short port )
+ {
+22. ACE_SOCK_Connector connector;
+23. ACE_INET_Addr addr (port, server);
+
+24. if (connector.connect (*this, addr) == -1)
+ {
+25. ACE_ERROR_RETURN ((LM_ERROR, &quot;%p\n&quot;, &quot;open&quot;), -1);
+ }
+
+26. mInitialized = 1;
+
+27. return(0);
+ }
+
+28. Client Client::operator&lt;&lt;( ACE_SString &amp; str )
+ {
+29. if( initialized() &amp;&amp; ! error() )
+ {
+30. char * cp = str.rep();
+
+31. mError = 0;
+
+32. if( this-&gt;send_n(cp,strlen(cp)) == -1 )
+ {
+33. mError = 1;
+ }
+ }
+34. else
+ {
+35. mError = 1;
+ }
+
+36. return *this ;
+ }
+
+37. Client Client::operator&lt;&lt; ( char * str )
+ {
+38. ACE_SString newStr(str);
+
+39. *this &lt;&lt; newStr;
+
+40. return *this ;
+ }
+
+41. Client Client::operator&lt;&lt; ( int n )
+ {
+ // ACE_SString newStr;
+ // newStr = n;
+
+42. char buf[1024];
+43. sprintf(buf,&quot;(%d)\n&quot;,n);
+44. ACE_SString newStr(buf);
+
+45. *this &lt;&lt; newStr;
+
+46. return *this;
+ }
+
+47. int main (int argc, char *argv[])
+ {
+48. const char *server_host = argc &gt; 1 ? argv[1] : ACE_DEFAULT_SERVER_HOST;
+49. u_short server_port = argc &gt; 2 ? ACE_OS::atoi (argv[2]) : ACE_DEFAULT_SERVER_PORT;
+50. int max_iterations = argc &gt; 3 ? ACE_OS::atoi (argv[3]) : 4;
+
+51. Client server(server_host,server_port);
+
+52. if( ! server.initialized() )
+ {
+53. ACE_ERROR_RETURN ((LM_ERROR, &quot;%p\n&quot;, &quot;intialization&quot;), -1);
+ }
+
+
+54. for (int i = 0; i &lt; max_iterations; i++)
+ {
+55. server &lt;&lt; &quot;message = &quot; &lt;&lt; i+1;
+
+56. if ( server.error() )
+ {
+57. ACE_ERROR_RETURN ((LM_ERROR, &quot;%p\n&quot;, &quot;send&quot;), -1);
+ }
+58. else
+ {
+59. ACE_OS::sleep (1);
+ }
+ }
+
+60. if (server.close () == -1)
+ {
+61. ACE_ERROR_RETURN ((LM_ERROR, &quot;%p\n&quot;, &quot;close&quot;), -1);
+ }
+
+62. return 0;
+ }
+</PRE>
+</UL>
+
+<P>
+<HR WIDTH="100%"></P>
+
+<P>Now, the code description:</P>
+
+<OL></OL>
+
+<P>
+<HR WIDTH="100%"></P>
+
+<P>If you want to compile it yourself, here's the <A HREF="client.cpp">source</A>,
+the <A HREF="Makefile">Makefile</A>,
+and <A HREF="00SetEnv">Environment
+settings</A>. </P>
+
+<P>
+<HR WIDTH="100%"></P>
+
+<CENTER><P>[<A HREF="..">Tutorial
+Index</A>]</P></CENTER>
+
+</BODY>
+</HTML>
diff --git a/docs/tutorials/005/00SetEnv b/docs/tutorials/005/00SetEnv
new file mode 100644
index 00000000000..33ba8135007
--- /dev/null
+++ b/docs/tutorials/005/00SetEnv
@@ -0,0 +1,2 @@
+export WRAPPER_ROOT=/local/src/ACE/ACE_wrappers
+export LD_LIBRARY_PATH=$WRAPPER_ROOT/ace:$LD_LIBRARY_PATH
diff --git a/docs/tutorials/005/Makefile b/docs/tutorials/005/Makefile
new file mode 100644
index 00000000000..ec3e3bd243c
--- /dev/null
+++ b/docs/tutorials/005/Makefile
@@ -0,0 +1,42 @@
+#----------------------------------------------------------------------------
+# $Id$
+#
+# Makefile for the Reactor version of the Server Logging Daemon
+#----------------------------------------------------------------------------
+
+#----------------------------------------------------------------------------
+# Local macros
+#----------------------------------------------------------------------------
+
+BIN = server
+
+VLDLIBS = $(LDLIBS:%=%$(VAR))
+
+BUILD = $(VBIN)
+
+#----------------------------------------------------------------------------
+# Include macros and targets
+#----------------------------------------------------------------------------
+
+include $(WRAPPER_ROOT)/include/makeinclude/wrapper_macros.GNU
+include $(WRAPPER_ROOT)/include/makeinclude/macros.GNU
+include $(WRAPPER_ROOT)/include/makeinclude/rules.common.GNU
+include $(WRAPPER_ROOT)/include/makeinclude/rules.nonested.GNU
+include $(WRAPPER_ROOT)/include/makeinclude/rules.lib.GNU
+include $(WRAPPER_ROOT)/include/makeinclude/rules.bin.GNU
+include $(WRAPPER_ROOT)/include/makeinclude/rules.local.GNU
+
+#----------------------------------------------------------------------------
+# Local targets
+#----------------------------------------------------------------------------
+
+#----------------------------------------------------------------------------
+# Dependencies
+#----------------------------------------------------------------------------
+
+# DO NOT DELETE THIS LINE -- g++dep uses it.
+# DO NOT PUT ANYTHING AFTER THIS LINE, IT WILL GO AWAY.
+
+
+
+# IF YOU PUT ANYTHING HERE IT WILL GO AWAY
diff --git a/docs/tutorials/005/acceptor b/docs/tutorials/005/acceptor
new file mode 100644
index 00000000000..45409e4ec3e
--- /dev/null
+++ b/docs/tutorials/005/acceptor
@@ -0,0 +1,6 @@
+
+1. #include "ace/Acceptor.h"
+2. #include "ace/SOCK_Acceptor.h"
+
+3. typedef ACE_Acceptor <Logging_Handler, ACE_SOCK_ACCEPTOR> Logging_Acceptor;
+
diff --git a/docs/tutorials/005/handler b/docs/tutorials/005/handler
new file mode 100644
index 00000000000..d987f4c34ff
--- /dev/null
+++ b/docs/tutorials/005/handler
@@ -0,0 +1,81 @@
+
+1. #include "ace/SOCK_Acceptor.h"
+2. #include "ace/Reactor.h"
+
+
+3. class Logging_Handler : public ACE_Svc_Handler<ACE_SOCK_STREAM, ACE_NULL_SYNCH>
+ {
+
+ public:
+
+4. Logging_Handler (void)
+ {
+ }
+
+5. virtual void destroy (void)
+ {
+6. g_reactor->cancel_timer (this);
+7. this->peer ().close ();
+ }
+
+8. virtual int open (void *)
+ {
+9. ACE_INET_Addr addr;
+
+10. if (this->peer ().get_remote_addr (addr) == -1)
+11. return -1;
+12. else
+ {
+13. ACE_OS::strncpy (this->peer_name_, addr.get_host_name (), MAXHOSTNAMELEN + 1);
+
+14. if (g_reactor->register_handler(this, ACE_Event_Handler::READ_MASK) == -1)
+15. ACE_ERROR_RETURN ((LM_ERROR, "(%P|%t) can't register with reactor\n"), -1);
+
+16. else if (g_reactor->schedule_timer (this, (const void *) this, ACE_Time_Value (2), ACE_Time_Value (2)) == -1)
+17. ACE_ERROR_RETURN ((LM_ERROR, "can'(%P|%t) t register with reactor\n"), -1);
+
+18. else
+19. ACE_DEBUG ((LM_DEBUG, "(%P|%t) connected with %s\n", this->peer_name_));
+
+20. return 0;
+ }
+ }
+
+21. virtual int close (u_long)
+ {
+22. this->destroy ();
+23. return 0;
+ }
+
+ protected:
+
+24. virtual int handle_input (ACE_HANDLE)
+ {
+25. char buf[128];
+26. memset(buf,0,sizeof(buf));
+
+27. switch( this->peer().recv(buf,sizeof buf) )
+ {
+28. case -1:
+29. ACE_ERROR_RETURN ((LM_ERROR, "(%P|%t) %p bad read\n", "client logger"), -1);
+30. case 0:
+31. ACE_ERROR_RETURN ((LM_ERROR, "(%P|%t) closing log daemon (fd = %d)\n", this->get_handle ()), -1);
+32. default:
+33. ACE_DEBUG ((LM_DEBUG, "(%P|%t) from client: %s",buf));
+ }
+
+34. return 0;
+ }
+
+35. virtual int handle_timeout (const ACE_Time_Value &tv, const void *arg)
+ {
+36. ACE_ASSERT (arg == this);
+37. ACE_DEBUG ((LM_DEBUG, "(%P|%t) handling timeout from this = %u\n", this));
+38. return 0;
+ }
+
+ private:
+
+39. char peer_name_[MAXHOSTNAMELEN + 1];
+
+ };
diff --git a/docs/tutorials/005/main b/docs/tutorials/005/main
new file mode 100644
index 00000000000..36c67561463
--- /dev/null
+++ b/docs/tutorials/005/main
@@ -0,0 +1,36 @@
+1. #include "ace/Reactor.h"
+
+2. ACE_Reactor * g_reactor;
+
+3. static sig_atomic_t finished = 0;
+4. extern "C" void handler (int) { finished = 1; }
+
+5. static const u_short PORT = ACE_DEFAULT_SERVER_PORT;
+
+6. int main (int argc, char *argv[])
+ {
+7. g_reactor = new ACE_Reactor;
+
+ // Acceptor factory.
+8. Logging_Acceptor peer_acceptor;
+
+9. if (peer_acceptor.open (ACE_INET_Addr (PORT)) == -1)
+10. ACE_ERROR_RETURN ((LM_ERROR, "%p\n", "open"), -1);
+
+11. else if (g_reactor->register_handler (&peer_acceptor, ACE_Event_Handler::READ_MASK) == -1)
+12. ACE_ERROR_RETURN ((LM_ERROR, "registering service with ACE_Reactor\n"), -1);
+
+13. ACE_Sig_Action sa ((ACE_SignalHandler) handler, SIGINT);
+
+ // Run forever, performing logging service.
+
+14. ACE_DEBUG ((LM_DEBUG, "(%P|%t) starting up server logging daemon\n"));
+
+ // Perform logging service until QUIT_HANDLER receives SIGINT.
+15. while ( !finished )
+16. g_reactor->handle_events ();
+
+17. ACE_DEBUG ((LM_DEBUG, "(%P|%t) shutting down server logging daemon\n"));
+
+18. return 0;
+ }
diff --git a/docs/tutorials/005/page01.html b/docs/tutorials/005/page01.html
new file mode 100644
index 00000000000..dc308378ba2
--- /dev/null
+++ b/docs/tutorials/005/page01.html
@@ -0,0 +1,59 @@
+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 3.2//EN">
+<HTML>
+<HEAD>
+ <TITLE>ACE Tutorial 005</TITLE>
+ <META NAME="GENERATOR" CONTENT="Mozilla/3.0Gold (Win95; I) [Netscape]">
+ <META NAME="Author" CONTENT="Billy Quinn">
+ <META NAME="Description" CONTENT="A first step towards using ACE productively">
+</HEAD>
+<BODY text = "#000000" link="#000fff" vlink="#ff0f0f" bgcolor="#ffffff">
+
+
+<CENTER><P><B><FONT SIZE=+2>ACE&nbsp;Tutorial 005<BR>
+Creating a Multithreaded Server</FONT></B></P></CENTER>
+
+<P>
+<HR WIDTH="100%"></P>
+
+<P>In this tutorial, we will build a little on what we learned in the previous
+tutorials and add a few extras. The end result of the tutorial will be
+a multi-threaded server which will handle large volume of connections by
+spawning off seperate threads.</P>
+
+<P>
+<HR WIDTH="100%"></P>
+
+<P>To begin, let's ask ourselves the same thing we did at the beginning
+of tutorial 001:</P>
+
+<UL>
+<P>What do you need to create a server?</P>
+</UL>
+
+<OL>
+<OL>
+<LI>Something which accepts connections from clients</LI>
+
+<LI>Something which handles established connections</LI>
+
+<LI>A main program loop that handles it all</LI>
+</OL>
+</OL>
+
+<P>Previously, we created a solution which addressed each one of these
+questions specifically. However, this solution was based on one thread
+of program flow which does not extract the full potential of a multi-threaded
+operating system like LINUX or Windows95. This tutorial specifically addresses
+this issue and examines how to use multiple threads , each handling a seperate
+connection. We will start by examining a solution which uses the ACE package
+to spawn threads, and then I will introduce an alternative solution based
+on the active object paradigm. <P>
+
+<P>
+<HR WIDTH="100%"></P>
+
+<CENTER><P>[<A HREF="..">Tutorial Index</A>] [<A HREF="page02.html">Continue
+This Tutorial</A>] </P></CENTER>
+
+</BODY>
+</HTML>
diff --git a/docs/tutorials/005/page02.html b/docs/tutorials/005/page02.html
new file mode 100644
index 00000000000..cfd57b3d5c5
--- /dev/null
+++ b/docs/tutorials/005/page02.html
@@ -0,0 +1,178 @@
+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 3.2//EN">
+<HTML>
+<HEAD>
+ <TITLE>ACE Tutorial 005</TITLE>
+ <META NAME="GENERATOR" CONTENT="Mozilla/3.0Gold (Win95; I) [Netscape]">
+ <META NAME="Author" CONTENT="Billy Quinn">
+ <META NAME="Description" CONTENT="A first step towards using ACE productively">
+</HEAD>
+<BODY text = "#000000" link="#000fff" vlink="#ff0f0f" bgcolor="#ffffff">
+
+
+<CENTER><P><B><FONT SIZE=+2>ACE&nbsp;Tutorial 005<BR>
+Creating a MultiThreaded Server </FONT></B></P></CENTER>
+
+<P>
+<HR WIDTH="100%"></P>
+
+<P>The program is actually small enough to fit into a single source file.
+To make things a little easier to follow, though, I've broken it up into
+four parts: <TT>main, acceptor , subclassed reactor and handler</TT>. Each
+is presented with line numbers and description. Because it is a single
+file, you won't see <I>#include</I> directives you may expect. Wait 'till
+the final page and see the whole thing put together before you worry about
+things like that.</P>
+
+<P>
+<HR WIDTH="100%"></P>
+
+<P>We begin by looking at the main portion program:</P>
+
+<UL>
+<PRE>
+1. ACE_Reactor * g_reactor;
+
+2. static sig_atomic_t finished = 0;
+
+3. class Logging_Handler;
+
+
+4. extern &quot;C&quot; void handler (int) { finished = 1; }
+
+5. static const u_short PORT = ACE_DEFAULT_SERVER_PORT;
+
+
+6. int main (int argc, char *argv[])
+ {
+7. g_reactor = new ACE_Reactor;
+
+8. Logging_Acceptor peer_acceptor;
+
+9. if (peer_acceptor.open (ACE_INET_Addr (PORT)) == -1)
+10. ACE_ERROR_RETURN ((LM_ERROR, &quot;%p\n&quot;, &quot;open&quot;), -1);
+
+11. else if (g_reactor-&gt;register_handler (&amp;peer_acceptor, ACE_Event_Handler::READ_MASK) == -1)
+12. ACE_ERROR_RETURN ((LM_ERROR, &quot;registering service with ACE_Reactor\n&quot;), -1);
+</PRE>
+
+<PRE>13. ACE_Sig_Action sa ((ACE_SignalHandler) handler, SIGINT);
+
+14. ACE_DEBUG ((LM_DEBUG, &quot;(%P|%t) starting up server logging daemon\n&quot;));
+
+15. while ( !finished )
+16. g_reactor-&gt;handle_events ();
+
+
+17. ACE_DEBUG ((LM_DEBUG, &quot;(%P|%t) shutting down server logging daemon\n&quot;));</PRE>
+
+<PRE>18. return 0;
+
+ }
+
+
+
+</PRE>
+</UL>
+
+<P>
+<HR></P>
+
+<OL>
+<LI>To keep things simple, we again have a global reactor object. This
+time, however, we are keeping a pointer to it. Since C++&nbsp;isn't too
+clear about initialization of global/static objects I chose to dynamically
+create the object in <I>main</I> rather than having it global.</LI>
+
+<LI><I>finished</I> is an atomic data type which we will use to tell us
+the server should exit. It will be set when the program receives an <I>interrupt</I>
+signal.</LI>
+
+<LI>Declare the class Logging_Handler, so that we can declare it as a friend
+class in our <I>Derived_Reactor</I> object. This is necessary because we need
+access to the counter in the derived reactors private variable space.</LI>
+
+<LI>This &quot;C&quot; function will process the <I>interrupt</I> signal
+if it is received by the program. All that it needs to do is set the <I>finished</I>
+flag which our main loop will look at as an indication to exit.</LI>
+
+<LI>The simple variable <I>PORT</I> is statically initialized to a default
+value. This is where the server will listen for new client connection requests.</LI>
+
+<LI>A typical <I>main</I> signature. Although we give ourselves access
+to the command-line arguments, we won't be using them. A more robust example
+might allow specifying the port number or other information via the command-line.</LI>
+
+<LI>The global reactor pointer is now initialized. We could have just as
+easily have chosen to create it on the stack and set <I>g_reactor</I> to
+point to the stack variable. Either way, it gives us more control than
+declaring it outside of <I>main</I>.</LI>
+
+<LI>Now, we create the object which will accept new client requests. Unlike
+the reactor, we did create this one on the stack. In the long run it really
+doesn't matter since Unix is very nice about cleaning up allocated memory
+when the program exits.</LI>
+
+<LI>We now use the acceptor's <I>open</I> member function to get it up
+and running. We create the object of type <I>ACE_INET_ADDR</I> with the port number
+as the argument and pass this object into the open function. ACE wrapper
+now take care of the low level details of preparing the port for incoming
+data , and we are now ready to register the acceptor object with the reactor
+to start accepting requests.</LI>
+
+<LI>We use <I>ACE_ERROR_RETURN</I> to get ourselves out if the <I>open</I>
+call fails. This is a handy and consistent method for reporting nasty things.</LI>
+
+<LI>If the <I>open</I> was successful we will get to here. It is now time
+to register the acceptor with the reactor so that the acceptor's member
+functions will be called when there is activity to be dealt with. Notice
+that we have to pass the address of the acceptor since we created the object
+on the stack instead of with <I>new</I>. Also notice that we're asking
+the reactor to only respond to <I>READ</I> type events. These will be client
+connection requests.</LI>
+
+<LI>Another call to <I>ACE_ERROR_RETURN</I> if the registration failed.</LI>
+
+<LI>An <I>ACE_Sig_Action</I> object is created and given the address of
+the <I>handle</I> &quot;C&quot;&nbsp;function declared above. With that
+function is associated the signal <I>SIGINT</I>. If the program receives
+this signal at any time, the <I>handle</I> function will be called. This
+is our way to cleanly exit the program. There is a much cleaner way to
+do this by creating an object which is registered with the reactor. However,
+I&nbsp;don't want to get into reactor-registered signal handlers at this
+time, so we're going with the easy-out.</LI>
+
+<LI><I>ACE_DEBUG</I> is another function like <I>ACE_ERROR_RETURN</I> that
+we can use to provide consistent messages to the user. Here, we just want
+to report that the program has started.</LI>
+
+<LI>Loop forever unless <I>finished</I> gets a non-zero value. Since the
+only way that can happen is by receipt of an <I>interrupt</I> signal, we
+will keep running until somebody <I>kill</I>s us with that (<I>kill -SIGINT&nbsp;process-id</I>).</LI>
+
+<LI>As always, allow the reactor to handle any events that are generated
+on it's registered event handlers.</LI>
+
+<LI>Announce our departure.</LI>
+
+<LI>Return a successful exit value to the operating system.</LI>
+</OL>
+
+<P>We got a little sloppy by not <I>delete</I>ing the reactor we dynamically
+allocated at the beginning of <I>main</I>. We really should do that for
+sake of completeness and neat programming. Even if we forget though, Unix
+is good about freeing up a program's memory (automatic and dynamically
+allocated)&nbsp;when the program exits.</P>
+
+<P>When compared with our last tutorial, this <TT>main</TT> portion of
+the server has changed very little in our conversion to a multi threaded
+server. Next, we will create our <I>Logging_Handler</I> class which is
+used in <TT>main.</TT></P>
+
+<P>
+<HR WIDTH="100%"></P>
+
+<CENTER><P>[<A HREF="../../Tutorial">Tutorial Index</A>] [<A HREF="page01.html">Previous
+Page</A>] [<A HREF="page03.html">Continue This Tutorial</A>] </P></CENTER>
+
+</BODY>
+</HTML>
diff --git a/docs/tutorials/005/page03.html b/docs/tutorials/005/page03.html
new file mode 100644
index 00000000000..74bce80827c
--- /dev/null
+++ b/docs/tutorials/005/page03.html
@@ -0,0 +1,67 @@
+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 3.2//EN">
+<HTML>
+<HEAD>
+ <TITLE>ACE Tutorial 005</TITLE>
+ <META NAME="GENERATOR" CONTENT="Mozilla/3.0Gold (Win95; I) [Netscape]">
+ <META NAME="Author" CONTENT="Billy Quinn">
+ <META NAME="Description" CONTENT="A first step towards using ACE productively">
+</HEAD>
+<BODY text = "#000000" link="#000fff" vlink="#ff0f0f" bgcolor="#ffffff">
+
+
+<CENTER><P><B><FONT SIZE=+2>ACE&nbsp;Tutorial 005<BR>
+Creating a MultiThreaded Server </FONT></B></P></CENTER>
+
+<P>
+<HR WIDTH="100%"></P>
+
+<P>This is what we do to create an acceptor from the ACE&nbsp;template:</P>
+
+<UL>
+<PRE>
+
+1. #include &quot;ace/Acceptor.h&quot;
+
+2. #include &quot;ace/SOCK_Acceptor.h&quot;
+
+
+
+3. typedef ACE_Acceptor &lt;Logging_Handler, ACE_SOCK_ACCEPTOR&gt; Logging_Acceptor;
+
+</PRE>
+</UL>
+
+<P>
+<HR></P>
+
+<P>Now, if you think that was difficult, you may as well give up now.</P>
+
+<OL>
+<LI>The <I>Acceptor</I> header file defines the template we're about to
+use. This is a totally generic object where all of the hard work as already
+been done.</LI>
+
+<LI>Because we want to accept connections on an <I>ACE_SOCK_Stream</I>,
+we have to pull in this header. It provides the API details that we will
+need.</LI>
+
+<LI>Finally, create a <I>Logging_Acceptor</I> object based on the <I>ACE_Acceptor</I>
+template. The first parameter <I>Logging_Handler</I> is an object we will
+develop on the next page. This object will be created by the template-generated
+code whenever a new connection request is accepted. The second parameter
+tells the template what kind of acceptor to create. It is most important
+that the first-parameter object and the second parameter be consistent
+in the connetion types used.</LI>
+</OL>
+
+<P>Obviously we're doing things a bit out of order here: <I>main</I> won't
+be happy until it knows what a <I>Logging_Acceptor</I> is and the acceptor
+won't be happy until it knows what a <I>Logging_Handler</I> is. The next
+page pulls in this definition for us, and after the declaration of the
+<I>Logging_Handler</I>, we will tie all the pieces of the server together.</P>
+
+<CENTER><P>[<A HREF="../../Tutorial">Tutorial Index</A>] [<A HREF="page02.html">Previous
+Page</A>] [<A HREF="page04.html">Continue This Tutorial</A>] </P></CENTER>
+
+</BODY>
+</HTML>
diff --git a/docs/tutorials/005/page04.html b/docs/tutorials/005/page04.html
new file mode 100644
index 00000000000..641fd89da24
--- /dev/null
+++ b/docs/tutorials/005/page04.html
@@ -0,0 +1,126 @@
+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 3.2//EN">
+<HTML>
+<HEAD>
+ <TITLE>ACE Tutorial 005</TITLE>
+ <META NAME="GENERATOR" CONTENT="Mozilla/3.0Gold (Win95; I) [Netscape]">
+ <META NAME="Author" CONTENT="Billy Quinn">
+ <META NAME="Description" CONTENT="A first step towards using ACE productively">
+</HEAD>
+<BODY text = "#000000" link="#000fff" vlink="#ff0f0f" bgcolor="#ffffff">
+
+
+<CENTER><P><B><FONT SIZE=+2>ACE&nbsp;Tutorial 005<BR>
+Creating a MultiThreaded Server </FONT></B></P></CENTER>
+
+<P>
+<HR WIDTH="100%"></P>
+
+<P>Our next step in building the multi-theaded server is to define the
+classes which will carry out the processing after a connection has been
+accepted by the acceptor. Given that the overall purpose of this tutorial
+was to have a thread and reactor for each connection, we could also implement
+multiple connections per reactor. Althought this is not necessary in this
+example, it is beneficial to examine how this could be done for future
+tutorials that will build on the concept. To do this we need some mechanism
+for tracking the number of connections that are associated with a particular
+reactor. We can achieve this by deriving a class from base class <I>ACE_Reactor</I>
+and holding a private variable associated with the derived <I>Logging_Handler
+</I>object. This will be incremented and decremented as client connections
+are added and deleted respectively. Yeah, I know this mechanism is crude
+..... but show me another way of doing it !! The dervied class definition
+is as follows : </P>
+
+<UL>
+<PRE>1. class Reactor_Derived : public ACE_Reactor
+
+ {
+
+
+
+ public :
+
+2. Reactor_Derived() : ()
+
+ {
+
+3. counter = 0;
+
+ }
+
+
+
+4. virtual ~Reactor_Derived()
+
+ {
+
+
+
+ }
+
+
+
+ private :
+
+5. friend class Logging_Handler;
+
+
+
+ // counter is used to keep track of the number of service handlers
+
+ // registered with this reactor
+
+6. int counter;
+
+ };
+
+
+
+
+
+</PRE>
+</UL>
+
+<P>
+<HR WIDTH="100%"></P>
+
+<P>Here's the step-by-step explanation:</P>
+
+<OL>
+<LI>Declaration for the subclassed-reactor which is derived from the ACE_Reactor
+base class. In our <I>Logging_Handler</I> object we will declare an object of this type instead of declaring an object of type <I>ACE_Reactor</I>.</LI>
+
+<LI>Constructor for our subclassed-reactor. Notice the empty parentheses
+- This calls the parent class constructor.</LI>
+
+<LI>Set our connection counter variable to 0.</LI>
+
+<LI>Our default constructor does nothing. We've moved anything with failure
+potential into the <I>open</I> function. Should the constructor be virtual?</LI>
+
+<LI>Declare the Logging_Handler class to be a friend class of this object.
+This allows the Logging_Handler class to access our private connection
+counter variable , allowing it to detect when all of our connections have
+been terminated for this reactor object.</LI>
+
+<LI>Our private counter variable which is used to count the number of connections
+registered with this reactor. </LI>
+
+<P>Now that the special reactor has been defined, we will define the final
+class in our multi-threaded server, the Logging_Handler.</P>
+
+<OL>
+<OL>
+<OL>
+<OL>
+<OL>
+<P>[<A HREF="..">Tutorial Index</A>] [<A HREF="page03.html">Previous Page</A>]
+[<A HREF="page05.html">Continue This Tutorial</A>] </P>
+</OL>
+</OL>
+</OL>
+</OL>
+</OL>
+</OL>
+
+</BODY>
+</HTML>
diff --git a/docs/tutorials/005/page05.html b/docs/tutorials/005/page05.html
new file mode 100644
index 00000000000..fb32ec93430
--- /dev/null
+++ b/docs/tutorials/005/page05.html
@@ -0,0 +1,352 @@
+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 3.2//EN">
+<HTML>
+<HEAD>
+ <TITLE>ACE Tutorial 005</TITLE>
+ <META NAME="GENERATOR" CONTENT="Mozilla/3.0Gold (Win95; I) [Netscape]">
+ <META NAME="Author" CONTENT="Billy Quinn">
+ <META NAME="Description" CONTENT="A first step towards using ACE productively">
+</HEAD>
+<BODY text = "#000000" link="#000fff" vlink="#ff0f0f" bgcolor="#ffffff">
+
+
+<CENTER><P><B><FONT SIZE=+2>ACE&nbsp;Tutorial 005<BR>
+Creating a MultiThreaded Server </FONT></B></P></CENTER>
+
+<P>
+<HR WIDTH="100%"></P>
+
+<P>The final piece in our multi-threaded server is the <I>Logging_Handler</I>
+class.&nbsp;As you might guess, this is the part which has been modified most
+from our previous server tutorial to include threads. This is a perfect demonstration
+of the decoupling effect of using the acceptor/connector model, whereby
+the connection oriented code is seperated from the actual processing which
+occurs after the connection has been established. :</P>
+
+<UL>
+<PRE>1. class Logging_Handler : public ACE_Svc_Handler&lt;ACE_SOCK_STREAM, ACE_NULL_SYNCH&gt;
+
+ {
+
+
+
+ public:
+
+
+
+2. Logging_Handler (void) { };
+
+
+
+3. virtual void destroy (void)
+
+ {
+
+4. if (this-&gt;thread_reactorP-&gt;remove_handler(this,
+
+ ACE_Event_Handler::READ_MASK | ACE_Event_Handler::DONT_CALL) == -1)
+
+5. ACE_ERROR_RETURN ((LM_ERROR, &quot;can'(%P|%t) t remove service from reactor\n&quot;), -1);
+
+
+
+ // Decrement the handler tracking variable in the reactor to
+
+ // indicate this service handler has terminated
+
+6. --thread_reactorP-&gt;counter;
+
+
+
+7. this-&gt;peer ().close ();
+
+8. delete this;
+
+ }
+
+
+
+9. static void *run_thread(Logging_Handler *this_)
+
+ {
+
+10. Reactor_Derived thread_reactor;
+
+
+
+11. this_-&gt;thread_reactorP = &amp;thread_reactor;
+
+12. if (thread_reactor.register_handler(this_, ACE_Event_Handler::READ_MASK) == -1)
+
+13. ACE_ERROR_RETURN ((LM_ERROR,&quot;can'(%P|%t) t register with reactor\n&quot;), -1);
+
+
+ // Increment our handler counter to account for this service handler
+
+14. ++thread_reactor.counter;
+
+
+
+15. while( thread_reactor.counter &gt; 0 )
+
+ {
+
+ // If thread_reactor.counter = 0 then we have no more service
+ // handlers connected to the reactor. We set a timeout value
+ // of 1 second so that handle_events returns to us every
+ // second. This gives us a chance to check the count. We
+ // need to do this because handle_events will block even
+ // when there are no connections. A better method might be
+ // to use ACE_Reactor_Notify but we'll save that for a later
+ // tutorial.
+
+16. thread_reactor.handle_events(ACE_Time_Value(1,0));
+
+ }
+
+ }
+
+
+
+17. virtual int open (void *)
+
+ {
+
+18. ACE_Thread::spawn(&amp;Logging_Handler::run_thread,this);
+
+19. return 0;
+
+ }
+
+
+
+20. virtual int close (u_long)
+
+ {
+
+21. this-&gt;destroy ();
+
+22. return 0;
+
+ }
+
+
+
+ protected:
+
+
+
+23. virtual int handle_input (ACE_HANDLE)
+
+ {
+
+24. char buf[128];
+
+25. memset(buf,0,sizeof(buf));
+
+
+
+26. switch( this-&gt;peer().recv(buf,sizeof buf) )
+
+ {
+
+27. case -1:
+
+28. ACE_ERROR_RETURN ((LM_ERROR, &quot;(%P|%t) %p bad read\n&quot;, &quot;client logger&quot;), -1);
+
+29. case 0:
+
+30. ACE_ERROR_RETURN ((LM_ERROR, &quot;(%P|%t) closing log daemon (fd = %d)\n&quot;, this-&gt;get_handle ()), -1);
+
+31. default:
+
+32. ACE_DEBUG ((LM_DEBUG, &quot;(%P|%t) from client : %s&quot;,buf)); </PRE>
+
+<PRE> }
+
+
+
+33. return 0;
+
+ }
+
+
+
+
+
+ private:
+
+34. Reactor_Derived *thread_reactorP;
+
+
+
+ };
+
+
+
+</PRE>
+</UL>
+
+<P>
+<HR WIDTH="100%"></P>
+
+<P>Here's the step-by-step explanation:</P>
+
+<OL>
+<LI>We've apparently decided to be bold and use yet another ACE template
+to create our <I>Logging_Handler</I> object. From the manual, the <I>ACE_Svc_Handler</I>
+template <I>defines the interface for a service that exchanges data with
+its connected peer</I>. The first template argument specifies the kind
+of connection we want to have. As mentioned on the previous page, this
+<B>must</B> be compatible with the data type used to accept the connection.
+As for the second argument, I have no idea. Somebody please explain this
+to me.</LI>
+
+<LI>Our default constructor does nothing. We've moved anything with failure
+potential into the <TT>open()</TT> function. Should the constructor be virtual?</LI>
+
+<LI><TT>destroy()</TT> is called by our close function which is called when the
+<I>Logging_Handler</I> object needs to be cleaned up due to termination</LI>
+
+<LI>Unregister the <I>Logging_Handler</I> object (this) from the reactor
+which is associated with this <I>Logging_Handler</I> object. The reactor
+address is gotten by dereferencing the pointer (thread_reactor_P in this case)
+which is the pointer to the local reactor object. We pass in two flags
+to the remove_handler call, because the <I>Logging_Handler</I> was registered
+in read mode and therefore needs to be unregistered in the same manner.
+The flag DONT_CALL prevents the reactor from calling the <TT>destroy</TT> function of the <I>Logging_Handler</I> object, which is the default for unregistering an event handler. We have to use this flag because we would enter an infinite recursive loop due to the fact that the <TT>remove_handler</TT> is located in the <TT>destroy</TT> method and that would recall the <TT>destroy</TT> method by default, which would call the <TT>remove_handler</TT> method again, and so on. This is not good!! - and we would eventually blow the stack therefore causing all kinds of nasty things to happen.</LI>
+
+
+<LI>If this is called an error has occured while unregistering the <I>Logging_Handler</I>
+object so generate an error.</LI>
+
+<LI>Decrement the counter for the reactor which is associated with this
+<I>Logging_Handler</I>. This indicates that another connection has gone
+away and the reactor's main loop (<TT>handle_events()</TT>) will not loop any more if this was the last connection registered with the reactor.
+Since we will only have one connection per reactor , this is not really
+necessary in this tutorial , but our next tutorial will use this idea for
+multiple connections per reactor.</LI>
+
+<LI>Close the connection to the client. Notice that we use the <I>peer()</I>
+member function generated by the template. We should never need direct
+access to the actual connection object.</LI>
+
+<LI>Delete the current <I>Logging_Handler</TT> object from memory - This is necessary
+because memory has been dynamically allocated so it will not clean up automatically
+when the scope of this <I>Logging_Handler</I> object runs out.</LI>
+
+<LI>Our thread entry point. This is the function that is called when a
+<I>Logging_Handler</I> spawns off a thread to handle a specific question. Note
+it accepts a pointer to an object of type <I>Logging_Handler</I>. This is necessary
+since the function is static so it is shared among all of the instantiated
+objects of type <I>Logging_Handler</I>, and we need a reference to the object
+we are dealing with at run time.</LI>
+
+<LI>Declare the automatic variable of type <I>Reactor_Derived</I>. The variable is declared automatic so that it is placed on the thread's stack, and is therefore deleted automatically when the thread exits. Since we are running each reactor in a seperate thread, it is **vital** that the reactor is declared within the thread in which it will be demultiplexing events. If this variable is declared outside of the thread it will not respond to any event handlers which are registered within the thread. </LI>
+
+<LI>Sets up the pointer to point to our automatic variable thread_reactor.
+By doing this, we have a reference to this specfic thread reactor outside of the <I>run_thread</I>'s scope.</LI>
+
+<LI>Register the <I>Logging_Handler</I> object with the local reactor. If a successful registration occurs, the event handler will be placed in a table which the reactor iterates through to check for any data to be processed. The type of data which the reactor will check for on each of the event handlers is based on the flags which are passed into the <TT>register_handler</TT> function for that event handler. Note how the flag
+READ_MASK is passed in to indicate that the <I>Logging_Handler</I> object is expecting
+input of data.</LI>
+
+<LI>An error has occurred while registering in the handle (<TT>register_handler</TT>
+returned -1) so register an error using ACE_ERROR_RETURN predefined function
+call to handle error(write standard error,etc.).</LI>
+
+<LI>Increment the counter which is our tracking variable for the number
+of connections that the reactor is handling. As this tutorial has only
+one connection per reactor it is not really necessary here , but the concept
+will be used to handle multiple connections per reactor in the next tutorial.
+</LI>
+
+<LI>Loop while connections still are registered in the local reactor. The
+counter variable is used to hold the number of registered connections in
+the reactor. As this tutorial spawns a new thread for each connection ,
+each reactor will have only one connection registered with it. In this
+tutorial we could just exit when the connection is terminated, but as we
+will see in the next tutorial, multiple connections per reactor will be
+implemented to allow proper load balancing. </LI>
+
+<LI>Call the <TT>handle_events()</TT> function which causes the local reactor to iterate
+through all of its registered logging handlers and check for input. Note
+that we use the <I>ACE_Time_Value</I> class to set a timeout of 1 second. This
+breaks out of blocking mode so that the number of connections alive can
+be checked again . Apparently theres a bug in ACE whereby it blocks on
+a reactor even if no connections are present ?</LI>
+
+<LI>The <TT>open</TT> function contains all of our initialization logic.
+It is called by the acceptor when a new connection is accepted. If we fail
+to initialize for any reason, we will return an error code so that the
+acceptor can respond correctly. This could not be done in a constructor.</LI>
+
+<LI>Spawn off a thread to handle this <I>Logging_Handler.</I> The name
+of the function called is specifed as the first parameter, which in this
+case is the static function <TT>run_thread()</TT>. The thread then starts running
+at the function <TT>run_thread</TT>. Note also we need a reference to what connection
+handle we are referring to at run time (the variable this).</LI>
+
+<LI>Return 0 indicating success with the <TT>open</TT> function.</LI>
+
+<LI><TT>close()</TT> is called by the reactor when the <I>Logging_Handler</I> should
+terminate.</LI>
+
+<LI>Call the <TT>destroy()</TT> function which cleans up the <I>Logging_Handler</I> object (unregisters
+the reactor handles and deletes memory references..etc..)</LI>
+
+<LI>Return 0 to indicate success so the main reactor can continue running</LI>
+
+<LI><TI>handle_input()</TT> is where you do whatever your application requires
+when data is received from the client system. It is called by the reactor
+when it detects that one of its registered <I>Logging_Handlers </I>has
+some data ready to process.</LI>
+
+<LI>Create a storage space for the received data</LI>
+
+<LI>and make sure it is empty.</LI>
+
+<LI>Receive as much data as we can but don't overrun our buffer. For this
+simple example, we don't get too fancy. In a real application we would
+probably read some number of bytes (4?) and create a number from them.
+We would then use that number to decide how many more bytes to read. The
+number could be a simple byte count or it could be a packet type indicator
+which implies a bytecount.</LI>
+
+<LI>If <TT>recv()</TT> returns <I>-1</I> then there is something bad wrong
+with the connection so</LI>
+
+<LI>we return an <I>-1</I> to the reactor along with a failure message.
+We cannot continue after this.</LI>
+
+<LI>A <I>0</I> return from <TT>recv</TT> is not quite so bad. However, <TT>handle_input</TT>
+wouldn't have been called if there was no data to be read. So, we take
+this to be a sign that the client chose to shutdown the connection.</LI>
+
+<LI>Like the case above, we need to return a <I>-1</I> to the reactor so
+that we can be shutdown. </LI>
+
+<LI>Any other value from <I>recv</I> is taken to indicate the number of
+bytes received so</LI>
+
+<LI>we display the data to the user. In the real world, we could do an
+infinite number of things with the data.</LI>
+
+<LI>Return <I>0</I> if all is well with the receive so that the reactor
+will allow us to continue functioning.</LI>
+
+<LI>Declare the pointer which will store the address of the reactor associated
+with each <I>Logging_Handler</I>. Each <I>Logging_Handler</I> will have one of these.</LI>
+</OL>
+
+<P>Obviously this is a bit more complicated than the rest of the program.
+However, as you have probrably noticed, the application programmer is shielded
+from the underlying network programming details.</P>
+
+<P>
+<HR WIDTH="100%"></P>
+
+<CENTER><P>[<A HREF="..">Tutorial Index</A>] [<A HREF="page04.html">Previous
+Page</A>] [<A HREF="page06.html">Continue This Tutorial</A>] </P></CENTER>
+
+</BODY>
+</HTML>
diff --git a/docs/tutorials/005/page06.html b/docs/tutorials/005/page06.html
new file mode 100644
index 00000000000..4ce9694e95e
--- /dev/null
+++ b/docs/tutorials/005/page06.html
@@ -0,0 +1,42 @@
+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 3.2//EN">
+<HTML>
+<HEAD>
+ <TITLE>ACE Tutorial 005</TITLE>
+ <META NAME="GENERATOR" CONTENT="Mozilla/3.0Gold (Win95; I) [Netscape]">
+ <META NAME="Author" CONTENT="Billy Quinn">
+ <META NAME="Description" CONTENT="A first step towards using ACE productively">
+</HEAD>
+<BODY text = "#000000" link="#000fff" vlink="#ff0f0f" bgcolor="#ffffff">
+
+
+<CENTER><P><B><FONT SIZE=+2>ACE&nbsp;Tutorial 005<BR>
+Creating a MultiThreaded Server </FONT></B></P></CENTER>
+
+<P>
+<HR WIDTH="100%"></P>
+
+<P>Well, that's it for the first section of the fifth tutorial. Doug Schmidt
+proposed an alternative way to implement a multi-threaded server
+by using active objects. We will discuss this solution next as a carry
+on to tutorial five, even though the solution doesn't allow for multiple
+connections per reactor object. Click on &quot;Alternative solution&quot;
+below to carry on with tutorial five....</P>
+
+<P>As promised, the first solution fits together into a single file (server.cpp)</P>
+
+<UL>
+<LI><A HREF="00SetEnv">Environment Settings</A></LI>
+
+<LI><A HREF="Makefile">Makefile</A></LI>
+
+<LI><A HREF="server.cpp">server.cpp</A></LI>
+</UL>
+
+<P>
+<HR WIDTH="100%"></P>
+
+<CENTER><P>[<A HREF="..">Tutorial Index</A>] [<A HREF="page05.html">Previous
+Page</A>] [<A HREF="page07.html">Alternative Solution]</A> </P></CENTER>
+
+</BODY>
+</HTML>
diff --git a/docs/tutorials/005/page07.html b/docs/tutorials/005/page07.html
new file mode 100644
index 00000000000..565e15a4691
--- /dev/null
+++ b/docs/tutorials/005/page07.html
@@ -0,0 +1,333 @@
+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 3.2//EN">
+<HTML>
+<HEAD>
+ <TITLE>ACE Tutorial 005</TITLE>
+ <META NAME="GENERATOR" CONTENT="Mozilla/3.0Gold (Win95; I) [Netscape]">
+ <META NAME="Author" CONTENT="Billy Quinn">
+ <META NAME="Description" CONTENT="A first step towards using ACE productively">
+</HEAD>
+<BODY text = "#000000" link="#000fff" vlink="#ff0f0f" bgcolor="#ffffff">
+
+
+<CENTER><P><B><FONT SIZE=+2>ACE&nbsp;Tutorial 005<BR>
+Creating a MultiThreaded Server </FONT></B></P></CENTER>
+
+<P>
+<HR WIDTH="100%"></P>
+
+<UL>
+<P>The solution provided previously proposes a solution to deal with multiple connections per
+thread reactor, which is what we will build on in the next tutorial. In
+conjunction with this , it is beneficial to examine an alternative solution
+to this tutorial's specific purpose, which is to introduce the notion of
+a reactor per thread which will represent a single client connection to the server.
+As in the previous solution , the thread will exit immediately once the
+connection is terminated, so multiple connections per reactor are not implemented. However, the previous solution
+introduced a mechanism that would allow the reactor to handle multiple connections
+, by using the derived reactor object with a counter. It is important to
+note that the following solution does not provide this, but it addresses
+the specific objective of a reactor per thread. It also introduces the
+really cool notion of an active object using a function call (<TT>activate()</TT>)
+to start itself running. This idea will also be built upon in future tutorials.</P>
+</UL>
+
+<UL>
+<PRE>// $Id$
+
+// ============================================================================ //
+// = FILENAME
+// Connection_Handler.cpp
+//
+// = DESCRIPTION
+// This test illustrates how to create multiple threads, each
+//
+// = AUTHOR
+// Doug Schmidt
+//
+// ============================================================================
+
+
+1. #include &quot;ace/Acceptor.h&quot;
+2. #include &quot;ace/SOCK_Acceptor.h&quot;
+3. #include &quot;ace/Service_Config.h&quot;
+4. #include &quot;ace/Thread.h&quot;
+
+5. class Connection_Handler : public ACE_Svc_Handler&lt;ACE_SOCK_STREAM,
+6. ACE_NULL_SYNCH&gt;
+ {
+ public:
+7. virtual int open (void *);
+ // Initialize the &lt;Connection_Handler&gt; and make it an Active Object.
+
+8. virtual int close (u_long);
+ // Terminate the &lt;Connection_Handler&gt;.
+
+9. virtual int svc (void);
+ // Run the &lt;Connection_Handler&gt;'s main event loop.
+
+ protected:
+10. virtual int handle_close (ACE_HANDLE,
+11. ACE_Reactor_Mask);
+ // Signal the Active Object to stop when called.
+
+12. virtual int handle_input (ACE_HANDLE);
+ // Handle input from the client.
+
+13. virtual int handle_timeout (const ACE_Time_Value &amp;tv,
+14. const void *arg);
+ // Handle timeouts.
+
+15. virtual int handle_signal (int signum,
+16. siginfo_t *,
+17. ucontext_t *);
+ // Handle timeouts.
+
+18. sig_atomic_t finished_;
+ // Keeps track of whether we're done.
+ };
+
+19. int
+20. Connection_Handler::open (void *)
+ {
+21. ACE_DEBUG ((LM_DEBUG, &quot;(%P|%t) in open()\n&quot;));
+
+ // Create an Active Object.
+22. return this-&gt;activate (THR_NEW_LWP);
+ }
+
+23. Connection_Handler::close (u_long)
+ {
+24. ACE_DEBUG ((LM_DEBUG, &quot;(%P|%t) in close()\n&quot;));
+
+ // Shut ourself down.
+25. this-&gt;destroy ();
+26. return 0;
+ }
+
+27. int
+28. Connection_Handler::svc (void)
+ {
+29. ACE_DEBUG ((LM_DEBUG, &quot;(%P|%t) in svc()\n&quot;));
+
+30. this-&gt;finished_ = 0;
+
+ // Create our own personal Reactor just for this thread. Note that
+ // we create this on the stack of the thread since it's only used
+ // for the duration of this connection!
+
+31. ACE_Reactor reactor;
+
+ // Each &lt;ACE_Svc_Handler&gt; has its own &lt;ACE_Reactor *&gt;. By default, this
+ // points to the &lt;Acceptor's&gt; Reactor. However, we can point it to our
+ // local Reactor, which is what we do in this case.
+32. this-&gt;reactor (&amp;reactor);
+
+ // Register ourselves to handle input in this thread without
+ // blocking.
+33. if (this-&gt;reactor ()-&gt;register_handler
+34. (this, ACE_Event_Handler::READ_MASK) == -1)
+35. ACE_ERROR_RETURN ((LM_ERROR, &quot;can' (%P|%t) t register with reactor\n&quot;), -1);
+
+ // Schedule a timer.
+36. else if (this-&gt;reactor ()-&gt;schedule_timer
+37. (this,
+38. (const void *) this,
+39. ACE_Time_Value (2),
+40. ACE_Time_Value (2)) == -1)
+41. ACE_ERROR_RETURN ((LM_ERROR, &quot;(%P|%t) can't register with reactor\n&quot;), -1);
+42. else
+43. ACE_DEBUG ((LM_DEBUG, &quot; (%P|%t) connected with client\n&quot;));
+
+ // Keep looping until we receive SIGQUIT or the client shutsdown.
+
+44. while (this-&gt;finished_ == 0)
+ {
+45. ACE_DEBUG ((LM_DEBUG, &quot; (%P|%t) handling events\n&quot;));
+46. this-&gt;reactor ()-&gt;handle_events ();
+ }
+
+ // Cancel all pending timeouts.
+47. ACE_Service_Config::reactor ()-&gt;cancel_timer (this);
+
+ // Remove ourselves from the Reactor.
+48. this-&gt;reactor ()-&gt;remove_handler
+49. (this, ACE_Event_Handler::READ_MASK | ACE_Event_Handler::DONT_CALL);
+
+ // Zero-out the Reactor field so it isn't accessed later on.
+50. this-&gt;reactor (0);
+
+51. ACE_DEBUG ((LM_DEBUG, &quot; (%P|%t) exiting svc\n&quot;));
+52. return 0;
+ }
+
+53. int
+54. Connection_Handler::handle_close (ACE_HANDLE,
+55. ACE_Reactor_Mask)
+ {
+56. ACE_DEBUG ((LM_DEBUG, &quot; (%P|%t) in handle_close \n&quot;));
+
+ // Signal the svc() event loop to shut down.
+57. this-&gt;finished_ = 1;
+58. return 0;
+ }
+
+59. int
+60. Connection_Handler::handle_input (ACE_HANDLE)
+ {
+61. char buf[BUFSIZ];
+
+62. ACE_DEBUG ((LM_DEBUG, &quot; (%P|%t) handle_input\n&quot;));
+
+63. switch (this-&gt;peer ().recv (buf, sizeof buf))
+ {
+64. case -1:
+65. ACE_ERROR_RETURN ((LM_ERROR, &quot; (%P|%t) %p bad read\n&quot;, &quot;client logger&quot;),
+66. -1);
+67. case 0:
+68. ACE_ERROR_RETURN ((LM_ERROR,
+69. &quot; (%P|%t) closing log daemon (fd = %d)\n&quot;,
+70. this-&gt;get_handle ()), -1);
+71. default:
+72. if (buf[0] == EOF)
+73. ACE_ERROR_RETURN ((LM_ERROR,
+74. &quot; (%P|%t) closing log daemon (fd = %d)\n&quot;,
+75. this-&gt;get_handle ()), -1);
+76. else
+77. ACE_DEBUG ((LM_DEBUG, &quot; (%P|%t) from client: %s&quot;, buf));
+ }
+
+78. return 0;
+ }
+
+79. int
+80. Connection_Handler::handle_signal (int signum,
+81. siginfo_t *,
+82. ucontext_t *)
+ {
+83. ACE_DEBUG ((LM_DEBUG, &quot;received signal %S\n&quot;, signum));
+84. this-&gt;finished_ = 1;
+85. return 0;
+ }
+
+86. int
+87. Connection_Handler::handle_timeout (const ACE_Time_Value &amp;tv,
+88. const void *arg)
+ {
+89. ACE_ASSERT (arg == this);
+90. ACE_DEBUG ((LM_DEBUG, &quot; (%P|%t) handling timeout from this = %u\n&quot;, this));
+91. return 0;
+ }
+
+ // Define an Acceptor for the &lt;Connection_Handler&gt;.
+
+92. typedef ACE_Acceptor &lt;Connection_Handler, ACE_SOCK_ACCEPTOR&gt;
+93. Connection_Acceptor;
+
+94. int
+95. main (int argc, char *argv[])
+ {
+96. ACE_Service_Config daemon (argv[0]);
+
+97. u_short port = argc &gt; 1 ? ACE_OS::atoi (argv[1]) : ACE_DEFAULT_SERVER_PORT;
+
+98. ACE_DEBUG ((LM_DEBUG, &quot; (%P|%t) in main\n&quot;));
+
+ // Acceptor factory.
+99. Connection_Acceptor peer_acceptor;
+
+ // Create an adapter to end the event loop.
+100. ACE_Sig_Adapter sa ((ACE_Sig_Handler_Ex)
+101. ACE_Service_Config::end_reactor_event_loop);
+
+ // Register the signal handler adapter.
+102. if (daemon.reactor ()-&gt;register_handler (SIGINT, &amp;sa) == -1)
+103. ACE_ERROR_RETURN ((LM_ERROR, &quot;%p\n&quot;, &quot;register_handler&quot;), -1);
+
+ // Open the Acceptor.
+104. else if (peer_acceptor.open (ACE_INET_Addr (port),
+105. daemon.reactor ()) == -1)
+106. ACE_ERROR_RETURN ((LM_ERROR, &quot;%p\n&quot;, &quot;open&quot;), -1);
+
+107. ACE_DEBUG ((LM_DEBUG, &quot; (%P|%t) starting up connection server\n&quot;));
+
+ // Perform connection service until we receive SIGINT.
+
+108. while (daemon.reactor_event_loop_done () == 0)
+109. daemon.run_reactor_event_loop ();
+
+110. ACE_DEBUG ((LM_DEBUG, &quot; (%P|%t) shutting down connection server\n&quot;));
+
+111. return 0;
+ }
+</PRE>
+</UL>
+
+<P>
+<HR WIDTH="100%"></P>
+
+<P>Here's a summary of how this solution works:</P>
+
+<UL>
+<P><TT>Main</TT>() : </P>
+
+<P>The <TT>main</TT> function of this active object solution is similar
+to the previously introduced solution in idea, but as you probrably noted
+the implementation is carried out differently. Both solutions use the concept
+of an acceptor listening on a certain port, which instantiate an object
+to handle the processing of data over the connection. However , the solution
+most recently described uses an object of type <I>ACE_Service_Config</I>
+which automatically provides a reactor, and a lot of method calls which
+can be used to control the reactor (for example method call end_reactor_event_loop
+stops the reactor iterating through its registered event handlers). In
+our first solution however, we had to explicitly create a reactor and write
+the function which ran and terminated the reactor. Notice also that the
+acceptor in the first solution had to be explicitly registered with
+our global reactor , whereas this is done transparently in the second solution
+by passing the address of the reactor into the open call of the <I>ACE_Acceptor</I>
+object. </P>
+
+<P>Connection handling : </P>
+
+<P>Two alternative methods have been introduced for handling a connection
+once a request for connection has been received by the <I>ACE_Acceptor</I>
+object. In our first solution, we used the <I>ACE_Thread</I> class to explicitly
+spawn a new thread which instantiates a reactor automatically when the
+thread is initialised. As you probrably remember however , we had to declare
+a static function so that we could pass the address of the <I>Logging_Handler
+</I>object to the function so we had a run time reference to what object was
+calling the thread. In the second solution presented, the use of active
+objects allows us to bypass the programming overhead of spawning the thread by simply
+activating the object when it is ready to run. This is acheived by the call
+to member function <TT>activate</TT> which automatically creates a new
+thread and causes the svc function of
+ the <I>Logging_Handler</I> object to be called.
+Since the <I>Logging_Handler</I> object is running in an independent
+thread, we dont have to worry about keeping track of a static thread function,
+which was necessary in the first solution presented. However, as mentioned
+in the introduction, the active object solution is a specific solution
+for a single reactor per thread each having one connection. Unlike the
+first solution, it does not cater for the reactor having more than once
+<I>Logging_Handler</I> objects to iterate through, which is what we will implement
+in future tutorials. (Note that an active object could be used to create the
+multiple-connections per reactor scenario. It is just this example which
+does not do so.)
+</P>
+</UL>
+
+<OL>
+<OL>
+<OL>
+<OL>
+<OL>
+<OL>
+<P>[<A HREF="../">Tutorial Index</A>] [<A HREF="page06.html">Previous
+Page</A>]</P>
+</OL>
+</OL>
+</OL>
+</OL>
+</OL>
+</OL>
+
+</BODY>
+</HTML>
diff --git a/docs/tutorials/005/server b/docs/tutorials/005/server
new file mode 100644
index 00000000000..9ee06c081a8
--- /dev/null
+++ b/docs/tutorials/005/server
Binary files differ
diff --git a/docs/tutorials/005/server.brk b/docs/tutorials/005/server.brk
new file mode 100644
index 00000000000..ba3d878a1da
--- /dev/null
+++ b/docs/tutorials/005/server.brk
@@ -0,0 +1,154 @@
+
+#include "ace/Acceptor.h"
+#include "ace/SOCK_Acceptor.h"
+#include "ace/Reactor.h"
+#include "ace/Thread.h"
+
+
+ACE_Reactor * g_reactor;
+
+static sig_atomic_t finished = 0;
+
+class Logging_Handler;
+
+extern "C" void handler (int) { finished = 1; }
+
+
+
+class Reactor_Derived : public ACE_Reactor
+{
+
+public :
+ Reactor_Derived() : ()
+ {
+ counter = 0;
+ }
+
+ virtual ~Reactor_Derived()
+ {
+ cout << "*****Calling the reactor destructor*****" << endl;
+ }
+
+private :
+ friend class Logging_Handler;
+
+ // counter is used to keep track of the number of service handlers
+ // registered with this reactor (Surely theres a better way ;-)
+ int counter;
+};
+
+class Logging_Handler : public ACE_Svc_Handler<ACE_SOCK_STREAM, ACE_NULL_SYNCH>
+{
+
+public:
+
+ Logging_Handler (void) { };
+
+ virtual void destroy (void)
+ {
+ if (this->thread_reactorP->remove_handler(this,
+ ACE_Event_Handler::READ_MASK | ACE_Event_Handler::DONT_CALL) == -1
+ )
+ ACE_ERROR_RETURN ((LM_ERROR, "can'(%P|%t) t remove service from reactor\n"), -1);
+
+ // Decrement the handler tracking variable in the reactor to
+ // indicate this service handler has terminated
+ --thread_reactorP->counter;
+
+ this->peer ().close ();
+ delete this;
+ }
+
+ static void *run_thread(Logging_Handler *this_)
+ {
+ Reactor_Derived thread_reactor;
+
+ this_->thread_reactorP = &thread_reactor;
+
+ // Increment our handler counter to account for this service handler
+ ++thread_reactor.counter;
+
+ if (thread_reactor.register_handler(this_, ACE_Event_Handler::READ_MASK) == -1)
+ ACE_ERROR_RETURN ((LM_ERROR,"can'(%P|%t) t register with reactor\n"), -1);
+
+ while( thread_reactor.counter > 0 )
+ {
+ // If thread_reactor.counter = 0 then we have no more service
+ // handlers connected to the reactor. We set a timeout value
+ // of 1 second so that the handle_events loop break out every
+ // second to check on the count ( because of it blocking
+ // even when there are no connections we need to do this)
+ thread_reactor.handle_events(ACE_Time_Value(1,0));
+ }
+ }
+
+ virtual int open (void *)
+ {
+ ACE_Thread::spawn(&Logging_Handler::run_thread,this);
+ return 0;
+ }
+
+ virtual int close (u_long)
+ {
+ this->destroy ();
+ return 0;
+ }
+
+protected:
+
+ virtual int handle_input (ACE_HANDLE)
+ {
+ char buf[128];
+ memset(buf,0,sizeof(buf));
+
+ switch( this->peer().recv(buf,sizeof buf) )
+ {
+ case -1:
+ ACE_ERROR_RETURN ((LM_ERROR, "(%P|%t) %p bad read\n", "client logger"), -1);
+ case 0:
+ ACE_ERROR_RETURN ((LM_ERROR, "(%P|%t) closing log daemon (fd = %d)\n", this->get_handle ()), -1);
+ default:
+ ACE_DEBUG ((LM_DEBUG, "(%p|%t) from client : %s",buf));
+ }
+
+ return 0;
+ }
+
+
+private:
+ Reactor_Derived *thread_reactorP;
+};
+
+
+typedef ACE_Acceptor <Logging_Handler, ACE_SOCK_ACCEPTOR> Logging_Acceptor;
+
+
+static const u_short PORT = ACE_DEFAULT_SERVER_PORT;
+
+int main (int argc, char *argv[])
+{
+ g_reactor = new ACE_Reactor;
+
+ // Acceptor factory.
+ Logging_Acceptor peer_acceptor;
+
+ if (peer_acceptor.open (ACE_INET_Addr (PORT)) == -1)
+ ACE_ERROR_RETURN ((LM_ERROR, "%p\n", "open"), -1);
+
+ else if (g_reactor->register_handler (&peer_acceptor, ACE_Event_Handler::READ_MASK) == -1)
+ ACE_ERROR_RETURN ((LM_ERROR, "registering service with ACE_Reactor\n"), -1);
+
+ ACE_Sig_Action sa ((ACE_SignalHandler) handler, SIGINT);
+
+ // Run forever, performing logging service.
+
+ ACE_DEBUG ((LM_DEBUG, "(%P|%t) starting up server logging daemon\n"));
+
+ // Perform logging service until QUIT_HANDLER receives SIGINT.
+ while ( !finished )
+ g_reactor->handle_events ();
+
+ ACE_DEBUG ((LM_DEBUG, "(%P|%t) shutting down server logging daemon\n"));
+
+ return 0;
+}
diff --git a/docs/tutorials/005/server.cpp b/docs/tutorials/005/server.cpp
new file mode 100644
index 00000000000..76687b3214b
--- /dev/null
+++ b/docs/tutorials/005/server.cpp
@@ -0,0 +1,149 @@
+// $Id$
+
+#include "ace/Acceptor.h"
+#include "ace/SOCK_Acceptor.h"
+#include "ace/Reactor.h"
+#include "ace/Thread.h"
+
+ACE_Reactor * g_reactor;
+
+static sig_atomic_t finished = 0;
+
+class Logging_Handler;
+
+extern "C" void handler (int) { finished = 1; }
+
+class Reactor_Derived : public ACE_Reactor
+{
+public:
+ Reactor_Derived() : ()
+ {
+ counter = 0;
+ }
+
+ virtual ~Reactor_Derived()
+ {
+ cout << "*****Calling the reactor destructor*****" << endl;
+ }
+
+private:
+ friend class Logging_Handler;
+
+ // counter is used to keep track of the number of service handlers
+ // registered with this reactor (Surely theres a better way ;-)
+ int counter;
+};
+
+class Logging_Handler : public ACE_Svc_Handler<ACE_SOCK_STREAM, ACE_NULL_SYNCH>
+{
+
+public:
+
+ Logging_Handler (void) { };
+
+ virtual void destroy (void)
+ {
+ if (this->thread_reactorP->remove_handler
+ (this,
+ ACE_Event_Handler::READ_MASK | ACE_Event_Handler::DONT_CALL) == -1)
+ ACE_ERROR_RETURN ((LM_ERROR, "can'(%P|%t) t remove service from reactor\n"), -1);
+
+ // Decrement the handler tracking variable in the reactor to
+ // indicate this service handler has terminated
+ --thread_reactorP->counter;
+
+ this->peer ().close ();
+ delete this;
+ }
+
+ static void *run_thread(Logging_Handler *this_)
+ {
+ Reactor_Derived thread_reactor;
+
+ this_->thread_reactorP = &thread_reactor;
+
+ // Increment our handler counter to account for this service handler
+ ++thread_reactor.counter;
+
+ if (thread_reactor.register_handler(this_, ACE_Event_Handler::READ_MASK) == -1)
+ ACE_ERROR_RETURN ((LM_ERROR,"can'(%P|%t) t register with reactor\n"), -1);
+
+ while( thread_reactor.counter > 0 )
+ {
+ // If thread_reactor.counter = 0 then we have no more service
+ // handlers connected to the reactor. We set a timeout value
+ // of 1 second so that the handle_events loop break out every
+ // second to check on the count ( because of it blocking
+ // even when there are no connections we need to do this)
+ thread_reactor.handle_events(ACE_Time_Value(1,0));
+ }
+ }
+
+ virtual int open (void *)
+ {
+ ACE_Thread::spawn(&Logging_Handler::run_thread,this);
+ return 0;
+ }
+
+ virtual int close (u_long)
+ {
+ this->destroy ();
+ return 0;
+ }
+
+protected:
+
+ virtual int handle_input (ACE_HANDLE)
+ {
+ char buf[128];
+ memset(buf,0,sizeof(buf));
+
+ switch( this->peer().recv(buf,sizeof buf) )
+ {
+ case -1:
+ ACE_ERROR_RETURN ((LM_ERROR, "(%P|%t) %p bad read\n", "client logger"), -1);
+ case 0:
+ ACE_ERROR_RETURN ((LM_ERROR, "(%P|%t) closing log daemon (fd = %d)\n", this->get_handle ()), -1);
+ default:
+ cout << "Received from client : " << buf;
+ }
+
+ return 0;
+ }
+
+
+private:
+ Reactor_Derived *thread_reactorP;
+};
+
+typedef ACE_Acceptor <Logging_Handler, ACE_SOCK_ACCEPTOR> Logging_Acceptor;
+
+static const u_short PORT = ACE_DEFAULT_SERVER_PORT;
+
+int main (int argc, char *argv[])
+{
+ g_reactor = new ACE_Reactor;
+
+ // Acceptor factory.
+ Logging_Acceptor peer_acceptor;
+
+ if (peer_acceptor.open (ACE_INET_Addr (PORT)) == -1)
+ ACE_ERROR_RETURN ((LM_ERROR, "%p\n", "open"), -1);
+
+ else if (g_reactor->register_handler (&peer_acceptor, ACE_Event_Handler::READ_MASK) == -1)
+ ACE_ERROR_RETURN ((LM_ERROR, "registering service with ACE_Reactor\n"), -1);
+
+ ACE_Sig_Action sa ((ACE_SignalHandler) handler, SIGINT);
+
+ // Run forever, performing logging service.
+
+ ACE_DEBUG ((LM_DEBUG, "(%P|%t) starting up server logging daemon\n"));
+
+ // Perform logging service until QUIT_HANDLER receives SIGINT.
+ while ( !finished )
+ g_reactor->handle_events ();
+
+ ACE_DEBUG ((LM_DEBUG, "(%P|%t) shutting down server logging daemon\n"));
+
+ return 0;
+}
diff --git a/docs/tutorials/005a/00SetEnv b/docs/tutorials/005a/00SetEnv
new file mode 100644
index 00000000000..33ba8135007
--- /dev/null
+++ b/docs/tutorials/005a/00SetEnv
@@ -0,0 +1,2 @@
+export WRAPPER_ROOT=/local/src/ACE/ACE_wrappers
+export LD_LIBRARY_PATH=$WRAPPER_ROOT/ace:$LD_LIBRARY_PATH
diff --git a/docs/tutorials/005a/DEADJOE b/docs/tutorials/005a/DEADJOE
new file mode 100644
index 00000000000..5ca99006390
--- /dev/null
+++ b/docs/tutorials/005a/DEADJOE
@@ -0,0 +1,158 @@
+
+*** Modified files in JOE when it aborted on Wed Jan 15 17:57:14 1997
+*** JOE was aborted because the terminal closed
+
+*** File 'server.cpp'
+
+#include "ace/Acceptor.h"
+#include "ace/SOCK_Acceptor.h"
+#include "ace/Reactor.h"
+#include "ace/Thread.h"
+
+
+ACE_Reactor * g_reactor;
+
+static sig_atomic_t finished = 0;
+
+
+extern "C" void handler (int) { finished = 1; }
+static void *thread_run(void *);
+// ----------------------------------------
+
+class Logging_Handler : public ACE_Svc_Handler<ACE_SOCK_STREAM, ACE_NULL_SYNCH>
+{
+
+public:
+
+ Logging_Handler (void)
+ {
+ cout << __LINE__ << " " << getpid() << endl;
+ thread_reactor = NULL;
+ }
+
+ ~Logging_Handler (void)
+ {
+ cout << __LINE__ << " " << getpid() << endl;
+ //Warning !!! segfault potential here !!!
+ // cerr << "Deleting " << thread_reactor << endl;
+ //thread_reactor->remove_handler(this,ACE_Event_Handler::READ_MASK);
+ //delete thread_reactor;
+ }
+
+ virtual void destroy (void)
+ {
+ cout << __LINE__ << " " << getpid() << endl;
+
+ g_reactor->cancel_timer (this);
+ this->peer ().close ();
+
+ //delete thread_reactor;
+ delete this;
+ }
+
+ static void *run_thread(Logging_Handler *this_)
+ {
+ cout << "run_thread in " << getpid() << endl;
+
+ this_->thread_reactor = new ACE_Reactor;
+
+ if (this_->thread_reactor->register_handler(this_, ACE_Event_Handler::READ_MASK) == -1)
+ ACE_ERROR_RETURN ((LM_ERROR, "(%P|%t) can't register with reactor\n"), -1);
+
+ else if (this_->thread_reactor->schedule_timer (this_, (const void *)this_, ACE_Time_Value (2), ACE_Time_Value (2)) == -1)
+ ACE_ERROR_RETURN ((LM_ERROR, "can'(%P|%t) t register with reactor\n"), -1);
+
+ else
+ ACE_DEBUG ((LM_DEBUG, "(%P|%t) connected with client \n"));
+
+ while(!finished)
+ this_->thread_reactor->handle_events() != -1;
+
+ }
+
+ virtual int open (void *)
+ {
+ cout << "open in " << getpid() << endl;
+
+ ACE_Thread::spawn(&Logging_Handler::run_thread,this);
+ return 0;
+ }
+
+ virtual int close (u_long)
+ {
+ cout << __LINE__ << " " << getpid() << endl;
+ this->destroy ();
+ return 0;
+ }
+
+protected:
+
+ virtual int handle_input (ACE_HANDLE)
+ {
+ char buf[128];
+ memset(buf,0,sizeof(buf));
+
+ cout << "handle_input in " << getpid() << endl;
+ switch( this->peer().recv(buf,sizeof buf) )
+ {
+ case -1:
+ ACE_ERROR_RETURN ((LM_ERROR, "(%P|%t) %p bad read\n", "client logger"), -1);
+ case 0:
+ ACE_ERROR_RETURN ((LM_ERROR, "(%P|%t) closing log daemon (fd = %d)\n", this->get_handle ()), -1);
+ default:
+ cout << "Data from client " << buf << endl;
+ // ACE_DEBUG ((LM_DEBUG, "(%P|%t) from client: %s",buf));
+ }
+
+ return 0;
+ }
+
+ virtual int handle_timeout (const ACE_Time_Value &tv, const void *arg)
+ {
+ ACE_ASSERT (arg == this);
+ // ACE_DEBUG ((LM_DEBUG, "(%P|%t) handling timeout from this = %u\n", this));
+ cout << "Timout in " << getpid() << endl;
+ return 0;
+ }
+
+private:
+ ACE_Reactor *thread_reactor;
+ char peer_name_[MAXHOSTNAMELEN + 1];
+
+};
+
+
+typedef ACE_Acceptor <Logging_Handler, ACE_SOCK_ACCEPTOR> Logging_Acceptor;
+
+
+static const u_short PORT = ACE_DEFAULT_SERVER_PORT;
+
+int main (int argc, char *argv[])
+{
+ g_reactor = new ACE_Reactor;
+
+ cout << "main is " << getpid() << endl;
+
+ // Acceptor factory.
+ Logging_Acceptor peer_acceptor;
+
+ if (peer_acceptor.open (ACE_INET_Addr (PORT)) == -1)
+ ACE_ERROR_RETURN ((LM_ERROR, "%p\n", "open"), -1);
+
+ else if (g_reactor->register_handler (&peer_acceptor, ACE_Event_Handler::READ_MASK) == -1)
+ ACE_ERROR_RETURN ((LM_ERROR, "registering service with ACE_Reactor\n"), -1);
+
+ ACE_Sig_Action sa ((ACE_SignalHandler) handler, SIGINT);
+
+ // Run forever, performing logging service.
+
+ ACE_DEBUG ((LM_DEBUG, "(%P|%t) starting up server logging daemon\n"));
+
+ // Perform logging service until QUIT_HANDLER receives SIGINT.
+ while ( !finished )
+ g_reactor->handle_events ();
+
+ ACE_DEBUG ((LM_DEBUG, "(%P|%t) shutting down server logging daemon\n"));
+
+ return 0;
+}
diff --git a/docs/tutorials/005a/Makefile b/docs/tutorials/005a/Makefile
new file mode 100644
index 00000000000..ec3e3bd243c
--- /dev/null
+++ b/docs/tutorials/005a/Makefile
@@ -0,0 +1,42 @@
+#----------------------------------------------------------------------------
+# $Id$
+#
+# Makefile for the Reactor version of the Server Logging Daemon
+#----------------------------------------------------------------------------
+
+#----------------------------------------------------------------------------
+# Local macros
+#----------------------------------------------------------------------------
+
+BIN = server
+
+VLDLIBS = $(LDLIBS:%=%$(VAR))
+
+BUILD = $(VBIN)
+
+#----------------------------------------------------------------------------
+# Include macros and targets
+#----------------------------------------------------------------------------
+
+include $(WRAPPER_ROOT)/include/makeinclude/wrapper_macros.GNU
+include $(WRAPPER_ROOT)/include/makeinclude/macros.GNU
+include $(WRAPPER_ROOT)/include/makeinclude/rules.common.GNU
+include $(WRAPPER_ROOT)/include/makeinclude/rules.nonested.GNU
+include $(WRAPPER_ROOT)/include/makeinclude/rules.lib.GNU
+include $(WRAPPER_ROOT)/include/makeinclude/rules.bin.GNU
+include $(WRAPPER_ROOT)/include/makeinclude/rules.local.GNU
+
+#----------------------------------------------------------------------------
+# Local targets
+#----------------------------------------------------------------------------
+
+#----------------------------------------------------------------------------
+# Dependencies
+#----------------------------------------------------------------------------
+
+# DO NOT DELETE THIS LINE -- g++dep uses it.
+# DO NOT PUT ANYTHING AFTER THIS LINE, IT WILL GO AWAY.
+
+
+
+# IF YOU PUT ANYTHING HERE IT WILL GO AWAY
diff --git a/docs/tutorials/005a/Makefile4broken b/docs/tutorials/005a/Makefile4broken
new file mode 100644
index 00000000000..872a0346132
--- /dev/null
+++ b/docs/tutorials/005a/Makefile4broken
@@ -0,0 +1,42 @@
+#----------------------------------------------------------------------------
+# @(#)Makefile 1.1 10/18/96
+#
+# Makefile for the Reactor version of the Server Logging Daemon
+#----------------------------------------------------------------------------
+
+#----------------------------------------------------------------------------
+# Local macros
+#----------------------------------------------------------------------------
+
+BIN = serverBroken
+
+VLDLIBS = $(LDLIBS:%=%$(VAR))
+
+BUILD = $(VBIN)
+
+#----------------------------------------------------------------------------
+# Include macros and targets
+#----------------------------------------------------------------------------
+
+include $(WRAPPER_ROOT)/include/makeinclude/wrapper_macros.GNU
+include $(WRAPPER_ROOT)/include/makeinclude/macros.GNU
+include $(WRAPPER_ROOT)/include/makeinclude/rules.common.GNU
+include $(WRAPPER_ROOT)/include/makeinclude/rules.nonested.GNU
+include $(WRAPPER_ROOT)/include/makeinclude/rules.lib.GNU
+include $(WRAPPER_ROOT)/include/makeinclude/rules.bin.GNU
+include $(WRAPPER_ROOT)/include/makeinclude/rules.local.GNU
+
+#----------------------------------------------------------------------------
+# Local targets
+#----------------------------------------------------------------------------
+
+#----------------------------------------------------------------------------
+# Dependencies
+#----------------------------------------------------------------------------
+
+# DO NOT DELETE THIS LINE -- g++dep uses it.
+# DO NOT PUT ANYTHING AFTER THIS LINE, IT WILL GO AWAY.
+
+
+
+# IF YOU PUT ANYTHING HERE IT WILL GO AWAY
diff --git a/docs/tutorials/005a/acceptor b/docs/tutorials/005a/acceptor
new file mode 100644
index 00000000000..45409e4ec3e
--- /dev/null
+++ b/docs/tutorials/005a/acceptor
@@ -0,0 +1,6 @@
+
+1. #include "ace/Acceptor.h"
+2. #include "ace/SOCK_Acceptor.h"
+
+3. typedef ACE_Acceptor <Logging_Handler, ACE_SOCK_ACCEPTOR> Logging_Acceptor;
+
diff --git a/docs/tutorials/005a/handler b/docs/tutorials/005a/handler
new file mode 100644
index 00000000000..d987f4c34ff
--- /dev/null
+++ b/docs/tutorials/005a/handler
@@ -0,0 +1,81 @@
+
+1. #include "ace/SOCK_Acceptor.h"
+2. #include "ace/Reactor.h"
+
+
+3. class Logging_Handler : public ACE_Svc_Handler<ACE_SOCK_STREAM, ACE_NULL_SYNCH>
+ {
+
+ public:
+
+4. Logging_Handler (void)
+ {
+ }
+
+5. virtual void destroy (void)
+ {
+6. g_reactor->cancel_timer (this);
+7. this->peer ().close ();
+ }
+
+8. virtual int open (void *)
+ {
+9. ACE_INET_Addr addr;
+
+10. if (this->peer ().get_remote_addr (addr) == -1)
+11. return -1;
+12. else
+ {
+13. ACE_OS::strncpy (this->peer_name_, addr.get_host_name (), MAXHOSTNAMELEN + 1);
+
+14. if (g_reactor->register_handler(this, ACE_Event_Handler::READ_MASK) == -1)
+15. ACE_ERROR_RETURN ((LM_ERROR, "(%P|%t) can't register with reactor\n"), -1);
+
+16. else if (g_reactor->schedule_timer (this, (const void *) this, ACE_Time_Value (2), ACE_Time_Value (2)) == -1)
+17. ACE_ERROR_RETURN ((LM_ERROR, "can'(%P|%t) t register with reactor\n"), -1);
+
+18. else
+19. ACE_DEBUG ((LM_DEBUG, "(%P|%t) connected with %s\n", this->peer_name_));
+
+20. return 0;
+ }
+ }
+
+21. virtual int close (u_long)
+ {
+22. this->destroy ();
+23. return 0;
+ }
+
+ protected:
+
+24. virtual int handle_input (ACE_HANDLE)
+ {
+25. char buf[128];
+26. memset(buf,0,sizeof(buf));
+
+27. switch( this->peer().recv(buf,sizeof buf) )
+ {
+28. case -1:
+29. ACE_ERROR_RETURN ((LM_ERROR, "(%P|%t) %p bad read\n", "client logger"), -1);
+30. case 0:
+31. ACE_ERROR_RETURN ((LM_ERROR, "(%P|%t) closing log daemon (fd = %d)\n", this->get_handle ()), -1);
+32. default:
+33. ACE_DEBUG ((LM_DEBUG, "(%P|%t) from client: %s",buf));
+ }
+
+34. return 0;
+ }
+
+35. virtual int handle_timeout (const ACE_Time_Value &tv, const void *arg)
+ {
+36. ACE_ASSERT (arg == this);
+37. ACE_DEBUG ((LM_DEBUG, "(%P|%t) handling timeout from this = %u\n", this));
+38. return 0;
+ }
+
+ private:
+
+39. char peer_name_[MAXHOSTNAMELEN + 1];
+
+ };
diff --git a/docs/tutorials/005a/main b/docs/tutorials/005a/main
new file mode 100644
index 00000000000..36c67561463
--- /dev/null
+++ b/docs/tutorials/005a/main
@@ -0,0 +1,36 @@
+1. #include "ace/Reactor.h"
+
+2. ACE_Reactor * g_reactor;
+
+3. static sig_atomic_t finished = 0;
+4. extern "C" void handler (int) { finished = 1; }
+
+5. static const u_short PORT = ACE_DEFAULT_SERVER_PORT;
+
+6. int main (int argc, char *argv[])
+ {
+7. g_reactor = new ACE_Reactor;
+
+ // Acceptor factory.
+8. Logging_Acceptor peer_acceptor;
+
+9. if (peer_acceptor.open (ACE_INET_Addr (PORT)) == -1)
+10. ACE_ERROR_RETURN ((LM_ERROR, "%p\n", "open"), -1);
+
+11. else if (g_reactor->register_handler (&peer_acceptor, ACE_Event_Handler::READ_MASK) == -1)
+12. ACE_ERROR_RETURN ((LM_ERROR, "registering service with ACE_Reactor\n"), -1);
+
+13. ACE_Sig_Action sa ((ACE_SignalHandler) handler, SIGINT);
+
+ // Run forever, performing logging service.
+
+14. ACE_DEBUG ((LM_DEBUG, "(%P|%t) starting up server logging daemon\n"));
+
+ // Perform logging service until QUIT_HANDLER receives SIGINT.
+15. while ( !finished )
+16. g_reactor->handle_events ();
+
+17. ACE_DEBUG ((LM_DEBUG, "(%P|%t) shutting down server logging daemon\n"));
+
+18. return 0;
+ }
diff --git a/docs/tutorials/005a/main.cpp b/docs/tutorials/005a/main.cpp
new file mode 100644
index 00000000000..76489b67452
--- /dev/null
+++ b/docs/tutorials/005a/main.cpp
@@ -0,0 +1,34 @@
+// $Id$
+#include "ace/Reactor.h"
+ACE_Reactor * g_reactor;
+
+static sig_atomic_t finished = 0;
+class Logging_Handler;
+
+extern "C" void handler (int) { finished = 1; }
+static void *thread_run(void *);
+
+static const u_short PORT = ACE_DEFAULT_SERVER_PORT;
+
+int main (int argc, char *argv[])
+{
+ g_reactor = new ACE_Reactor;
+
+ Logging_Acceptor peer_acceptor;
+
+ if (peer_acceptor.open (ACE_INET_Addr (PORT)) == -1)
+ ACE_ERROR_RETURN ((LM_ERROR, "%p\n", "open"), -1);
+
+ else if (g_reactor->register_handler (&peer_acceptor, ACE_Event_Handler::READ_MASK) == -1)
+ ACE_ERROR_RETURN ((LM_ERROR, "registering service with ACE_Reactor\n"), -1);
+
+ ACE_Sig_Action sa ((ACE_SignalHandler) handler, SIGINT);
+
+ ACE_DEBUG ((LM_DEBUG, "(%P|%t) starting up server logging daemon\n"));
+
+ while ( !finished )
+ g_reactor->handle_events ();
+
+ ACE_DEBUG ((LM_DEBUG, "(%P|%t) shutting down server logging daemon\n"));
+ return 0;
+}
diff --git a/docs/tutorials/005a/page01.html b/docs/tutorials/005a/page01.html
new file mode 100644
index 00000000000..b1f299d021b
--- /dev/null
+++ b/docs/tutorials/005a/page01.html
@@ -0,0 +1,59 @@
+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 3.2//EN">
+<HTML>
+<HEAD>
+ <TITLE>ACE Tutorial 002</TITLE>
+ <META NAME="GENERATOR" CONTENT="Mozilla/3.0Gold (Win95; I) [Netscape]">
+ <META NAME="Author" CONTENT="James CE Johnson">
+ <META NAME="Description" CONTENT="A first step towards using ACE productively">
+</HEAD>
+<BODY text = "#000000" link="#000fff" vlink="#ff0f0f" bgcolor="#ffffff">
+
+
+<CENTER><P><B><FONT SIZE=+2>ACE&nbsp;Tutorial 005<BR>
+Creating a Multithreaded Server</FONT></B></P></CENTER>
+
+<P>
+<HR WIDTH="100%"></P>
+
+<P>In this tutorial, we will build a little on what we learned in the previous
+tutorials and add a few extras. The end result of the tutorial will be
+a multi-threaded server which will handle large volume of connections more
+efficiently.</P>
+
+<P>
+<HR WIDTH="100%"></P>
+
+<P>To begin, let's ask ourselves the same thing we did at the beginning
+of tutorial 001:</P>
+
+<UL>
+<P>What do you need to create a server?</P>
+</UL>
+
+<OL>
+<OL>
+<LI>Something which accepts connections from clients</LI>
+
+<LI>Something which handles established connections</LI>
+
+<LI>A main program loop that handles it all</LI>
+</OL>
+</OL>
+
+<P>Previously, we created a solution which addressed each one of these
+questions specifically. However, this solution was based on one thread
+of program flow which doesnt extract the full potential of a multi-processing
+machine like LINUX or Windows95. This tutorial specifically addresses this
+issue and examines how to use multiple threads , each handling a seperate
+connection. We will start by examining a solution which uses the ACE package
+to spawn threads, and then I will introduce an alternative solution based
+on the active object paradigm. On we go...</P>
+
+<P>
+<HR WIDTH="100%"></P>
+
+<CENTER><P>[<A HREF="..">Tutorial Index</A>] [<A HREF="page02.html">Continue
+This Tutorial</A>] </P></CENTER>
+
+</BODY>
+</HTML>
diff --git a/docs/tutorials/005a/page02.html b/docs/tutorials/005a/page02.html
new file mode 100644
index 00000000000..e6698741fae
--- /dev/null
+++ b/docs/tutorials/005a/page02.html
@@ -0,0 +1,178 @@
+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 3.2//EN">
+<HTML>
+<HEAD>
+ <TITLE>ACE Tutorial 001</TITLE>
+ <META NAME="GENERATOR" CONTENT="Mozilla/3.0Gold (Win95; I) [Netscape]">
+ <META NAME="Author" CONTENT="James CE Johnson">
+ <META NAME="Description" CONTENT="A first step towards using ACE productively">
+</HEAD>
+<BODY text = "#000000" link="#000fff" vlink="#ff0f0f" bgcolor="#ffffff">
+
+
+<CENTER><P><B><FONT SIZE=+2>ACE&nbsp;Tutorial 005<BR>
+Creating a MulitThreaded Server </FONT></B></P></CENTER>
+
+<P>
+<HR WIDTH="100%"></P>
+
+<P>The program is actually small enough to fit into a single source file.
+To make things a little easier to follow, though, I've broken it up into
+three parts: <TT>main, acceptor and handler</TT>. Each is presented with
+line numbers and description. Because it is a single file, you won't see
+<I>#include</I> directives you may expect. Wait 'till the final page and
+see the whole thing put together before you worry about things like that.</P>
+
+<P>
+<HR WIDTH="100%"></P>
+
+<P>We begin by looking at the main portion program:</P>
+
+<UL>
+<PRE>
+
+1. ACE_Reactor * g_reactor;
+
+2. static sig_atomic_t finished = 0;
+
+3. class Logging_Handler;
+
+4. extern &quot;C&quot; void handler (int) { finished = 1; }
+5. static void *thread_run(void *);
+
+6. static const u_short PORT = ACE_DEFAULT_SERVER_PORT;
+
+7. int main (int argc, char *argv[])
+ {
+8. g_reactor = new ACE_Reactor;
+
+9. Logging_Acceptor peer_acceptor;
+
+10. if (peer_acceptor.open (ACE_INET_Addr (PORT)) == -1)
+11. ACE_ERROR_RETURN ((LM_ERROR, &quot;%p\n&quot;, &quot;open&quot;), -1);
+
+12. else if (g_reactor-&gt;register_handler (&amp;peer_acceptor, ACE_Event_Handler::READ_MASK) == -1)
+13. ACE_ERROR_RETURN ((LM_ERROR, &quot;registering service with ACE_Reactor\n&quot;), -1);
+
+14. ACE_Sig_Action sa ((ACE_SignalHandler) handler, SIGINT);
+
+15. ACE_DEBUG ((LM_DEBUG, &quot;(%P|%t) starting up server logging daemon\n&quot;));
+
+16. while ( !finished )
+17. g_reactor-&gt;handle_events ();
+
+18. ACE_DEBUG ((LM_DEBUG, &quot;(%P|%t) shutting down server logging daemon\n&quot;));
+
+19. return 0;
+ }
+
+</PRE>
+</UL>
+
+<P>
+<HR></P>
+
+<OL>
+<LI>To keep things simple, we again have a global reactor object. This
+time, however, we are keeping a pointer to it. Since C++&nbsp;isn't too
+clear about initialization of global/static objects I chose to dynamically
+create the object in <I>main</I> rather than having it global.</LI>
+
+<LI><I>finished</I> is an atomic data type which we will use to tell us
+the server should exit. It will be set when the program receives an <I>interrupt</I>
+signal.</LI>
+
+<LI>Declare the class Logging_Handler, so that we can declare it as a friend
+class in our derived Reactor object. This is necessary because we need
+access to the counter in the derived reactors private variable space.</LI>
+
+<LI>This &quot;C&quot; function will process the <I>interrupt</I> signal
+if it is received by the program. All that it needs to do is set the <I>finished</I>
+flag which our main loop will look at as an indication to exit.</LI>
+
+<LI>Declare the function prototype for the thread entry point. This is
+the function where the thread starts running in, hence it is declared static
+so the address of the function can be used to pass to the thread. Note
+that we can pass one argument into the thread - we will use this to pass
+the service handler object into the thread so it has a reference to the
+object which called it.</LI>
+
+<LI>The simple variable <I>PORT</I> is statically initialized to a default
+value. This is where the server will listen for new client connection requests.</LI>
+
+<LI>A typical <I>main</I> signature. Although we give ourselves access
+to the command-line arguments, we won't be using them. A more robust example
+might allow specifying the port number or other information via the command-line.</LI>
+
+<LI>The global reactor pointer is now initialized. We could have just as
+easily have chosen to create it on the stack and set <I>g_reactor</I> to
+point to the stack variable. Either way, it gives us more control than
+declaring it outside of <I>main</I>.</LI>
+
+<LI>Now, we create the object which will accept new client requests. Unlike
+the reactor, we did create this one on the stack. In the long run it really
+doesn't matter since Unix is very nice about cleaning up allocated memory
+when the program exits.</LI>
+
+<LI>We now use the acceptor's <I>open</I> member function to get it up
+and running. We create the object of type ACE_INET_addr with the port number
+as the argument and pass this object into the open function. ACE wrapper
+now take care of the low level details of preparing the port for incoming
+data , and we are now ready to register the acceptor object with the reactor
+to start accepting requests.</LI>
+
+<LI>We use <I>ACE_ERROR_RETURN</I> to get ourselves out if the <I>open</I>
+call fails. This is a handy and consistent method for reporting nasty things.</LI>
+
+<LI>If the <I>open</I> was successful we will get to here. It is now time
+to register the acceptor with the reactor so that the acceptor's member
+functions will be called when there is activity to be dealt with. Notice
+that we have to pass the address of the acceptor since we created the object
+on the stack instead of with <I>new</I>. Also notice that we're asking
+the reactor to only respond to <I>READ</I> type events. These will be client
+connection requests.</LI>
+
+<LI>Another call to <I>ACE_ERROR_RETURN</I> if the registration failed.</LI>
+
+<LI>An <I>ACE_Sig_Action</I> object is created and given the address of
+the <I>handle</I> &quot;C&quot;&nbsp;function declared above. With that
+function is associated the signal <I>SIGINT</I>. If the program receives
+this signal at any time, the <I>handle</I> function will be called. This
+is our way to cleanly exit the program. There is a much cleaner way to
+do this by creating an object which is registered with the reactor. However,
+I&nbsp;don't want to get into reactor-registered signal handlers at this
+time, so we're going with the easy-out.</LI>
+
+<LI><I>ACE_DEBUG</I> is another function like <I>ACE_ERROR_RETURN</I> that
+we can use to provide consistent messages to the user. Here, we just want
+to report that the program has started.</LI>
+
+<LI>Loop forever unless <I>finished</I> gets a non-zero value. Since the
+only way that can happen is by receipt of an <I>interrupt</I> signal, we
+will keep running until somebody <I>kill</I>s us with that (<I>kill -SIGINT&nbsp;process-id</I>).</LI>
+
+<LI>As always, allow the reactor to handle any events that are generated
+on it's registered event handlers.</LI>
+
+<LI>Announce our departure.</LI>
+
+<LI>Return a successful exit value to the operating system.</LI>
+</OL>
+
+<P>We got a little sloppy by not <I>delete</I>ing the reactor we dynamically
+allocated at the beginning of <I>main</I>. We really should do that for
+sake of completeness and neat programming. Even if we forget though, Unix
+is good about freeing up a program's memory (automatic and dynamically
+allocated)&nbsp;when the program exits.</P>
+
+<P>When compared with our last tutorial, this <TT>main</TT> portion of
+the server has changed very little in our conversion to a multi threaded
+server. Next, we will create our acceptor object which is used in <TT>main.</TT></P>
+
+<P>
+<HR WIDTH="100%"></P>
+
+<CENTER><P>[<A HREF="../../Tutorial">Tutorial Index</A>] [<A HREF="page01.html">Previous
+Page</A>] [<A HREF="page03.html">Continue This Tutorial</A>] </P></CENTER>
+
+</BODY>
+</HTML>
diff --git a/docs/tutorials/005a/page03.html b/docs/tutorials/005a/page03.html
new file mode 100644
index 00000000000..b68851b7a6e
--- /dev/null
+++ b/docs/tutorials/005a/page03.html
@@ -0,0 +1,65 @@
+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 3.2//EN">
+<HTML>
+<HEAD>
+ <TITLE>ACE Tutorial 001</TITLE>
+ <META NAME="GENERATOR" CONTENT="Mozilla/3.0Gold (Win95; I) [Netscape]">
+ <META NAME="Author" CONTENT="James CE Johnson">
+ <META NAME="Description" CONTENT="A first step towards using ACE productively">
+</HEAD>
+<BODY text = "#000000" link="#000fff" vlink="#ff0f0f" bgcolor="#ffffff">
+
+
+<CENTER><P><B><FONT SIZE=+2>ACE&nbsp;Tutorial 005<BR>
+Creating a MultiThreaded Server </FONT></B></P></CENTER>
+
+<P>
+<HR WIDTH="100%"></P>
+
+<P>This is what we do to create an acceptor from the ACE&nbsp;template:</P>
+
+<UL>
+<PRE>
+1. #include &quot;ace/Acceptor.h&quot;
+2. #include &quot;ace/SOCK_Acceptor.h&quot;
+
+3. typedef ACE_Acceptor &lt;Logging_Handler, ACE_SOCK_ACCEPTOR&gt; Logging_Acceptor;
+</PRE>
+</UL>
+
+<P>
+<HR></P>
+
+<P>Now, if you think that was difficult, you may as well give up now.</P>
+
+<OL>
+<LI>The <I>Acceptor</I> header file defines the template we're about to
+use. This is a totally generic object where all of the hard work as already
+been done.</LI>
+
+<LI>Because we want to accept connections on an <I>ACE_SOCK_Stream</I>,
+we have to pull in this header. It provides the API details that we will
+need.</LI>
+
+<LI>Finally, create a <I>Logging_Acceptor</I> object based on the <I>ACE_Acceptor</I>
+template. The first parameter <I>Logging_Handler</I> is an object we will
+develop on the next page. This object will be created by the template-generated
+code whenever a new connection request is accepted. The second parameter
+tells the template what kind of acceptor to create. It is most important
+that the first-parameter object and the second parameter be consistent
+in the connetion types used.</LI>
+</OL>
+
+<P>Obviously we're doing things a bit out of order here: <I>main</I> won't
+be happy until it knows what a <I>Logging_Acceptor</I> is and the acceptor
+won't be happy until it knows what a <I>Logging_Handler</I> is. The next
+page pulls in this last definition for us and after that we tie it all
+together.</P>
+
+<P>
+<HR WIDTH="100%"></P>
+
+<CENTER><P>[<A HREF="../../Tutorial">Tutorial Index</A>] [<A HREF="page02.html">Previous
+Page</A>] [<A HREF="page04.html">Continue This Tutorial</A>] </P></CENTER>
+
+</BODY>
+</HTML>
diff --git a/docs/tutorials/005a/page04.html b/docs/tutorials/005a/page04.html
new file mode 100644
index 00000000000..6f75aeca698
--- /dev/null
+++ b/docs/tutorials/005a/page04.html
@@ -0,0 +1,274 @@
+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 3.2//EN">
+<HTML>
+<HEAD>
+ <TITLE>ACE Tutorial 001</TITLE>
+ <META NAME="GENERATOR" CONTENT="Mozilla/3.0Gold (Win95; I) [Netscape]">
+ <META NAME="Author" CONTENT="James CE Johnson">
+ <META NAME="Description" CONTENT="A first step towards using ACE productively">
+</HEAD>
+<BODY text = "#000000" link="#000fff" vlink="#ff0f0f" bgcolor="#ffffff">
+
+
+<CENTER><P><B><FONT SIZE=+2>ACE&nbsp;Tutorial 005<BR>
+Creating a MultiThreaded Server </FONT></B></P></CENTER>
+
+<P>
+<HR WIDTH="100%"></P>
+
+<P>The final piece in our multi-threaded server is the <I>Logging_Handler</I>
+class.&nbsp;As you might guess, this is the part has been modified most
+from our previous server to include threads. This is a perfect demonstration
+of the decoupling effect of using the acceptor/connector model, whereby
+the connection oriented code is seperated from the actual processing which
+occurs after the connection has been established. :</P>
+
+<UL>
+<PRE>1. class Logging_Handler : public ACE_Svc_Handler&lt;ACE_SOCK_STREAM, ACE_NULL_SYNCH&gt;
+ {
+
+ public:
+
+2. Logging_Handler (void) { };
+
+3. virtual void destroy (void)
+ {
+4. if (this-&gt;thread_reactorP-&gt;remove_handler(this,
+ ACE_Event_Handler::READ_MASK | ACE_Event_Handler::DONT_CALL) == -1)
+5. ACE_ERROR_RETURN ((LM_ERROR, &quot;can'(%P|%t) t remove service from reactor\n&quot;), -1);
+
+ // Decrement the handler tracking variable in the reactor to
+ // indicate this service handler has terminated
+6. --thread_reactorP-&gt;counter;
+
+7. this-&gt;peer ().close ();
+8. delete this;
+ }
+
+11. static void *run_thread(Logging_Handler *this_)
+ {
+12. Reactor_Derived thread_reactor;
+
+13. this_-&gt;thread_reactorP = &amp;thread_reactor;
+
+ // Increment our handler counter to account for this service handler
+14. ++thread_reactor.counter;
+
+15. if (thread_reactor.register_handler(this_, ACE_Event_Handler::READ_MASK) == -1)
+16. ACE_ERROR_RETURN ((LM_ERROR,&quot;can'(%P|%t) t register with reactor\n&quot;), -1);
+
+17. while( thread_reactor.counter &gt; 0 )
+ {
+ // If thread_reactor.counter = 0 then we have no more service
+ // handlers connected to the reactor. We set a timeout value
+ // of 1 second so that the handle_events loop break out every
+ // second to check on the count ( because of it blocking
+ // even when there are no connections we need to do this)
+18. thread_reactor.handle_events(ACE_Time_Value(1,0));
+ }
+ }
+
+19. virtual int open (void *)
+ {
+20. ACE_Thread::spawn(&amp;Logging_Handler::run_thread,this);
+21. return 0;
+ }
+
+22. virtual int close (u_long)
+ {
+23. this-&gt;destroy ();
+24. return 0;
+ }
+
+ protected:
+
+25. virtual int handle_input (ACE_HANDLE)
+ {
+26. char buf[128];
+27. memset(buf,0,sizeof(buf));
+
+28. switch( this-&gt;peer().recv(buf,sizeof buf) )
+ {
+29. case -1:
+30. ACE_ERROR_RETURN ((LM_ERROR, &quot;(%P|%t) %p bad read\n&quot;, &quot;client logger&quot;), -1);
+31. case 0:
+32. ACE_ERROR_RETURN ((LM_ERROR, &quot;(%P|%t) closing log daemon (fd = %d)\n&quot;, this-&gt;get_handle ()), -1);
+33. default:
+34. ACE_DEBUG ((LM_DEBUG, &quot;(%P|%t) from client : %s&quot;,buf)); </PRE>
+
+<PRE> }
+
+35. return 0;
+ }
+
+
+ private:
+36. Reactor_Derived *thread_reactorP;
+
+ };
+
+</PRE>
+</UL>
+
+<P>
+<HR WIDTH="100%"></P>
+
+<P>Here's the step-by-step explanation:</P>
+
+<OL>
+<LI>We've apparently decided to be bold and use yet another ACE template
+to create our <I>Logging_Handler</I> object. From the manual, the <I>ACE_Svc_Handler</I>
+template <I>defines the interface for a service that exchanges data with
+its connected peer</I>. The first template argument specifies the kind
+of connection we want to have. As mentioned on the previous page, this
+<B>must</B> be compatible with the data type used to accept the connection.
+As for the second argument, I have no idea. Somebody please explain this
+to me.</LI>
+
+<LI>Our default constructor does nothing. We've moved anything with failure
+potential into the <I>open</I> function. Should the constructor be virtual?</LI>
+
+<LI>destroy() is called by our close function which is called when the
+service handler needs to be cleaned up due to termination</LI>
+
+<LI>Unregister the <I>Logging_Handler</I> object (this) from the reactor
+which is associated with this <I>Logging_Handler</I> object. The reactor
+address is got by dereferencing the pointer (thread_reactor_P in this case)
+which is the pointer to the local reactor object. We pass in two flags
+to the remove_handler call, because the <I>Logging_Handler</I> was registered
+in read mode and therefore needs to be unregistered in the same manner.
+The flag DONT_CALL tells the reactor not to callback on the remove_handler
+function ???!</LI>
+
+<LI>If this is called an error has occured while unregistering the <I>Logging_Handler</I>
+object so generate an error.</LI>
+
+<LI>Decrement the counter for the reactor which is associated with this
+<I>Logging_Handler</I>. This indicates that another connection has gone
+away and the reactor's main loop (handle_events) will not loop any more.
+Since we are only using one connecter per reactor , this is not really
+necessary in this tutorial , and our next tutorial will use this idea for
+multiple connections per reactor.</LI>
+
+<LI>Close the connection to the client. Notice that we use the <I>peer()</I>
+member function generated by the template. We should never need direct
+access to the actual connection object.</LI>
+
+<LI>Delete the current Logging_Handler object from memory - This is necessary
+because memory has been dynamically allocated so it wont clean up automatically
+when the scope of a function runs out.</LI>
+
+<LI>Out thread entry point. This is the function that is called when a
+service_handler spawns off a thread to handle a specific question. Note
+it accepts a pointer to an object of type Logging_Handler. This is necessary
+since the function is static so it is shared among all of the instantiated
+objects of type Logging_Handler, and we need a reference to the object
+we are dealing with at run time.</LI>
+
+<LI>Sets up the pointer to point to our automatic variable thread_reactor.
+This ensures that the memory used to hold the thread reactor is removed
+when it goes out of scope.</LI>
+
+<LI>Register the Logging_Handler with the local reactor. Note how the flag
+READ_MASK is passed in to indicate that the Logging_Handler object is expecting
+input of data.</LI>
+
+<LI>An error has occurred while registering in the handle (register_hanler
+returned -1) so register an error using ACE_ERROR_RETURN predefined function
+call to handle error(write standard error,etc.)</LI>
+
+<LI>Increment the counter which is our tracking variable for the number
+of connections that the reactor is handling. As this tutorial has only
+one connection per reactor it is not really necessary here , but the concept
+will be used to handle multiple connections per reactor in the next tutorial.
+</LI>
+
+<LI>Loop while connections still are registered in the local reactor. The
+counter variable is used to hold the number of registered connections in
+the reactor. As this tutorial spawns a new thread for each connection ,
+each reactor will have only one connection registered with it. In this
+tutorial we could just exit when the connection is terminated, but as we
+will see in the next tutorial, multiple connections per reactor will be
+implemented to allow proper load balancing. </LI>
+
+<LI>Call the handle_events function which iterated through all of its registered
+connection handlers and checks for input. Note that we use the ACE_Time_Value
+class to set a time out of 1 second. This breaks out of blocking mode so
+that the number of connections can be checked again . A bug in ACE whereby
+it blocks on a reactor even if no connections are present ?</LI>
+
+<LI>The <I>open</I> function contains all of our initialization logic.
+It is called by the acceptor when a new connection is accepted. If we fail
+to initialize for any reason, we will return an error code so that the
+acceptor can respond correctly. This could not be done in a constructor.</LI>
+
+<LI>Spawn off a thread to handle this connection handler. The name of the
+function called is specifed as the first parameter, which in this case
+is the static function run_thread. The thread then starts running at the
+function run_thread. Note also we need a reference to what connection handle
+we are referring to at run time (the this variable).</LI>
+
+<LI>Return 0 indicating success with the open function.</LI>
+
+<LI>Close() is called by the reactor when the connection handler should
+terminate.</LI>
+
+<LI>Call the destroy function which cleans up the connection handler (unregisters
+the reactor handles and deletes memory references..etc..)</LI>
+
+<LI>Return 0 to indicate success so we can continue running</LI>
+
+<LI><I>handle_input</I> is where you do whatever your application requires
+when data is received from the client system.</LI>
+
+<LI>Create a storage space for the received data</LI>
+
+<LI>and make sure it is empty.</LI>
+
+<LI>Receive as much data as we can but don't overrun our buffer. For this
+simple example, we don't get too fancy. In a real application we would
+probably read some number of bytes (4?) and create a number from them.
+We would then use that number to decide how many more bytes to read. The
+number could be a simple byte count or it could be a packet type indicator
+which implies a bytecount.</LI>
+
+<LI>If <I>recv</I> returns <I>-1</I> then there is something bad wrong
+with the connection so</LI>
+
+<LI>we return an <I>-1</I> to the reactor along with a failure message.
+We cannot continue after this.</LI>
+
+<LI>A <I>0</I> return from <I>recv</I> is not quite so bad. However, <I>handle_input</I>
+wouldn't have been called if there was no data to be read. So, we take
+this to be a sign that the client chose to shutdown the connection.</LI>
+
+<LI>Like the case above, we need to return a <I>-1</I> to the reactor so
+that we can be shutdown. </LI>
+
+<LI>Any other value from <I>recv</I> is taken to indicate the number of
+bytes received so</LI>
+
+<LI>we display the data to the user. In the real world, we could do an
+infinite number of things with the data.</LI>
+
+<LI>Return <I>0</I> if all is well with the receive so that the reactor
+will allow us to continue functioning.</LI>
+
+<LI>Declare the pointer which will store the address of the reactor associated
+with each connection handler. Each connection handler will have one of
+these.</LI>
+</OL>
+
+<P>Obviously this is a bit more complicated than the rest of the program.
+Still, you see there isn't a lot of networking knowlege needed to get this
+up and going. There are unfortunately several questions that I can't answer
+(such as the <I>delete this</I> issue) but given time, I'm sure we'll all
+figure it out.</P>
+
+<P>
+<HR WIDTH="100%"></P>
+
+<CENTER><P>[<A HREF="..">Tutorial Index</A>] [<A HREF="page03.html">Previous
+Page</A>] [<A HREF="page05.html">Continue This Tutorial</A>] </P></CENTER>
+
+</BODY>
+</HTML>
diff --git a/docs/tutorials/005a/page04a.html b/docs/tutorials/005a/page04a.html
new file mode 100644
index 00000000000..c9ca8e50ede
--- /dev/null
+++ b/docs/tutorials/005a/page04a.html
@@ -0,0 +1,97 @@
+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 3.2//EN">
+<HTML>
+<HEAD>
+ <TITLE>ACE Tutorial 001</TITLE>
+ <META NAME="GENERATOR" CONTENT="Mozilla/3.0Gold (Win95; I) [Netscape]">
+ <META NAME="Author" CONTENT="James CE Johnson">
+ <META NAME="Description" CONTENT="A first step towards using ACE productively">
+</HEAD>
+<BODY text = "#000000" link="#000fff" vlink="#ff0f0f" bgcolor="#ffffff">
+
+
+<CENTER><P><B><FONT SIZE=+2>ACE&nbsp;Tutorial 005<BR>
+Creating a MultiThreaded Server </FONT></B></P></CENTER>
+
+<P>
+<HR WIDTH="100%"></P>
+
+<P>Since each Logging_Handler has a reactor, we could implement multiple
+connections per reactor. To do this we need some mechanism for tracking
+the number of connections that are associated with a particular reactor.
+We can achieve this by deriving a class from base class ACE_Reactor and
+holding a private variable associated with the derived object. This will
+be incremented and decremented as client connections are added and deleted
+respectively. I know this mechanism is crude ..... but show me another
+way of doing it !! The dervied class definition is as follows : </P>
+
+<UL>
+<PRE>1. class Reactor_Derived : public ACE_Reactor
+ {
+
+ public :
+2. Reactor_Derived() : ()
+ {
+3. counter = 0;
+ }
+
+4. virtual ~Reactor_Derived()
+ {
+
+ }
+
+ private :
+5. friend class Logging_Handler;
+
+ // counter is used to keep track of the number of service handlers
+ // registered with this reactor (Surely theres a better way ;-)
+6. int counter;
+ };
+
+
+</PRE>
+</UL>
+
+<P>
+<HR WIDTH="100%"></P>
+
+<P>Here's the step-by-step explanation:</P>
+
+<OL>
+<LI>Declaration for the subclassed-reactor which is derived from the ACE_Reactor
+base class</LI>
+
+<LI>Constructor for our subclassed-reactor. Notice the empty parentheses
+- This calls the parent class constructor.</LI>
+
+<LI>Set our connection counter variable to 0.</LI>
+
+<LI>Our default constructor does nothing. We've moved anything with failure
+potential into the <I>open</I> function. Should the constructor be virtual?</LI>
+
+<LI>Declare the Logging_Handler class to be a friend class of this object.
+This allows the Logging_Handler class to access our private connection
+counter variable , allowing it to detect when all of our connections have
+been terminated for this reactor object.</LI>
+
+<LI>Our private counter variable which is used to count the number of connections
+registered with this reactor. </LI>
+
+<P>Now that the special reactor has been defined, we will define the final
+class in our multi-threaded server, the Logging_Handler.</P>
+
+<OL>
+<OL>
+<OL>
+<OL>
+<OL>
+<P>[<A HREF="..">Tutorial Index</A>] [<A HREF="page03.html">Previous Page</A>]
+[<A HREF="page05.html">Continue This Tutorial</A>] </P>
+</OL>
+</OL>
+</OL>
+</OL>
+</OL>
+</OL>
+
+</BODY>
+</HTML>
diff --git a/docs/tutorials/005a/page05.html b/docs/tutorials/005a/page05.html
new file mode 100644
index 00000000000..c9ca8e50ede
--- /dev/null
+++ b/docs/tutorials/005a/page05.html
@@ -0,0 +1,97 @@
+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 3.2//EN">
+<HTML>
+<HEAD>
+ <TITLE>ACE Tutorial 001</TITLE>
+ <META NAME="GENERATOR" CONTENT="Mozilla/3.0Gold (Win95; I) [Netscape]">
+ <META NAME="Author" CONTENT="James CE Johnson">
+ <META NAME="Description" CONTENT="A first step towards using ACE productively">
+</HEAD>
+<BODY text = "#000000" link="#000fff" vlink="#ff0f0f" bgcolor="#ffffff">
+
+
+<CENTER><P><B><FONT SIZE=+2>ACE&nbsp;Tutorial 005<BR>
+Creating a MultiThreaded Server </FONT></B></P></CENTER>
+
+<P>
+<HR WIDTH="100%"></P>
+
+<P>Since each Logging_Handler has a reactor, we could implement multiple
+connections per reactor. To do this we need some mechanism for tracking
+the number of connections that are associated with a particular reactor.
+We can achieve this by deriving a class from base class ACE_Reactor and
+holding a private variable associated with the derived object. This will
+be incremented and decremented as client connections are added and deleted
+respectively. I know this mechanism is crude ..... but show me another
+way of doing it !! The dervied class definition is as follows : </P>
+
+<UL>
+<PRE>1. class Reactor_Derived : public ACE_Reactor
+ {
+
+ public :
+2. Reactor_Derived() : ()
+ {
+3. counter = 0;
+ }
+
+4. virtual ~Reactor_Derived()
+ {
+
+ }
+
+ private :
+5. friend class Logging_Handler;
+
+ // counter is used to keep track of the number of service handlers
+ // registered with this reactor (Surely theres a better way ;-)
+6. int counter;
+ };
+
+
+</PRE>
+</UL>
+
+<P>
+<HR WIDTH="100%"></P>
+
+<P>Here's the step-by-step explanation:</P>
+
+<OL>
+<LI>Declaration for the subclassed-reactor which is derived from the ACE_Reactor
+base class</LI>
+
+<LI>Constructor for our subclassed-reactor. Notice the empty parentheses
+- This calls the parent class constructor.</LI>
+
+<LI>Set our connection counter variable to 0.</LI>
+
+<LI>Our default constructor does nothing. We've moved anything with failure
+potential into the <I>open</I> function. Should the constructor be virtual?</LI>
+
+<LI>Declare the Logging_Handler class to be a friend class of this object.
+This allows the Logging_Handler class to access our private connection
+counter variable , allowing it to detect when all of our connections have
+been terminated for this reactor object.</LI>
+
+<LI>Our private counter variable which is used to count the number of connections
+registered with this reactor. </LI>
+
+<P>Now that the special reactor has been defined, we will define the final
+class in our multi-threaded server, the Logging_Handler.</P>
+
+<OL>
+<OL>
+<OL>
+<OL>
+<OL>
+<P>[<A HREF="..">Tutorial Index</A>] [<A HREF="page03.html">Previous Page</A>]
+[<A HREF="page05.html">Continue This Tutorial</A>] </P>
+</OL>
+</OL>
+</OL>
+</OL>
+</OL>
+</OL>
+
+</BODY>
+</HTML>
diff --git a/docs/tutorials/005a/page06.html b/docs/tutorials/005a/page06.html
new file mode 100644
index 00000000000..2e5cde0ac9b
--- /dev/null
+++ b/docs/tutorials/005a/page06.html
@@ -0,0 +1,42 @@
+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 3.2//EN">
+<HTML>
+<HEAD>
+ <TITLE>ACE Tutorial 001</TITLE>
+ <META NAME="GENERATOR" CONTENT="Mozilla/3.0Gold (Win95; I) [Netscape]">
+ <META NAME="Author" CONTENT="James CE Johnson">
+ <META NAME="Description" CONTENT="A first step towards using ACE productively">
+</HEAD>
+<BODY text = "#000000" link="#000fff" vlink="#ff0f0f" bgcolor="#ffffff">
+
+
+<CENTER><P><B><FONT SIZE=+2>ACE&nbsp;Tutorial 005<BR>
+Creating a MultiThreaded Server </FONT></B></P></CENTER>
+
+<P>
+<HR WIDTH="100%"></P>
+
+<P>Well, that's it for the first section of the fifth tutorial. Doug Schmidt
+proposed a more &quot;elegant&quot; way to implement a multi-threaded server
+by using active objects. We will discuss this solution next as a carry
+on to tutorial five, even though the solution doesnt allow for multiple
+connections per reactor object. Click on &quot;Alternative solution&quot;
+below to carry on with tutorial five....</P>
+
+<P>As promised, this all fits together into a single file (server.cpp)</P>
+
+<UL>
+<LI><A HREF="00SetEnv">Environment Settings</A></LI>
+
+<LI><A HREF="Makefile">Makefile</A></LI>
+
+<LI><A HREF="server.cpp">server.cpp</A></LI>
+</UL>
+
+<P>
+<HR WIDTH="100%"></P>
+
+<CENTER><P>[<A HREF="..">Tutorial Index</A>] [<A HREF="page03.html">Previous
+Page</A>] [<A HREF="file://page5b.html">Alternative Solution]</A> </P></CENTER>
+
+</BODY>
+</HTML>
diff --git a/docs/tutorials/005a/server b/docs/tutorials/005a/server
new file mode 100644
index 00000000000..6aa3533662b
--- /dev/null
+++ b/docs/tutorials/005a/server
Binary files differ
diff --git a/docs/tutorials/005a/server.bck b/docs/tutorials/005a/server.bck
new file mode 100644
index 00000000000..03f05b5903a
--- /dev/null
+++ b/docs/tutorials/005a/server.bck
@@ -0,0 +1,160 @@
+
+#include "ace/Acceptor.h"
+#include "ace/SOCK_Acceptor.h"
+#include "ace/Reactor.h"
+#include "ace/Thread.h"
+
+
+ACE_Reactor * g_reactor;
+
+static sig_atomic_t finished = 0;
+
+class Logging_Handler;
+
+extern "C" void handler (int) { finished = 1; }
+static void *thread_run(void *);
+
+
+
+class Reactor_Derived : public ACE_Reactor
+{
+
+public :
+ Reactor_Derived() : ()
+ {
+ counter = 0;
+ }
+
+ virtual ~Reactor_Derived()
+ {
+ cout << "*****Calling the reactor destructor*****" << endl;
+ }
+
+private :
+ friend class Logging_Handler;
+
+ // counter is used to keep track of the number of service handlers
+ // registered with this reactor (Surely theres a better way ;-)
+ int counter;
+};
+
+class Logging_Handler : public ACE_Svc_Handler<ACE_SOCK_STREAM, ACE_NULL_SYNCH>
+{
+
+public:
+
+ Logging_Handler (void) { };
+
+ virtual void destroy (void)
+ {
+ if (this->thread_reactorP->remove_handler(this,
+ ACE_Event_Handler::READ_MASK | ACE_Event_Handler::DONT_CALL) == -1
+ )
+ ACE_ERROR_RETURN ((LM_ERROR, "can'(%P|%t) t remove service from reactor\n"), -1);
+
+ // Decrement the handler tracking variable in the reactor to
+ // indicate this service handler has terminated
+ --thread_reactorP->counter;
+
+ this->peer ().close ();
+ delete this;
+ }
+
+ static void *run_thread(Logging_Handler *this_)
+ {
+ Reactor_Derived thread_reactor;
+
+ this_->thread_reactorP = &thread_reactor;
+
+ // Increment our handler counter to account for this service handler
+ ++thread_reactor.counter;
+
+ if (thread_reactor.register_handler(this_, ACE_Event_Handler::READ_MASK) == -1)
+ ACE_ERROR_RETURN ((LM_ERROR,"can'(%P|%t) t register with reactor\n"), -1);
+
+ while( thread_reactor.counter > 0 )
+ {
+ // If thread_reactor.counter = 0 then we have no more service
+ // handlers connected to the reactor. We set a timeout value
+ // of 1 second so that the handle_events loop break out every
+ // second to check on the count ( because of it blocking
+ // even when there are no connections we need to do this)
+ thread_reactor.handle_events(ACE_Time_Value(1,0));
+ }
+ }
+
+ virtual int open (void *)
+ {
+ ACE_Thread::spawn(&Logging_Handler::run_thread,this);
+ return 0;
+ }
+
+ virtual int close (u_long)
+ {
+ this->destroy ();
+ return 0;
+ }
+
+protected:
+
+ virtual int handle_input (ACE_HANDLE)
+ {
+ char buf[128];
+ memset(buf,0,sizeof(buf));
+
+ cout << "handle_input in " << getpid() << endl;
+ switch( this->peer().recv(buf,sizeof buf) )
+ {
+ case -1:
+ ACE_ERROR_RETURN ((LM_ERROR, "(%P|%t) %p bad read\n", "client logger"), -1);
+ case 0:
+ ACE_ERROR_RETURN ((LM_ERROR, "(%P|%t) closing log daemon (fd = %d)\n", this->get_handle ()), -1);
+ default:
+ cout << "Data from client " << buf << endl;
+ }
+
+ return 0;
+ }
+
+
+private:
+ Reactor_Derived *thread_reactorP;
+ char peer_name_[MAXHOSTNAMELEN + 1];
+
+};
+
+
+typedef ACE_Acceptor <Logging_Handler, ACE_SOCK_ACCEPTOR> Logging_Acceptor;
+
+
+static const u_short PORT = ACE_DEFAULT_SERVER_PORT;
+
+int main (int argc, char *argv[])
+{
+ g_reactor = new ACE_Reactor;
+
+ cout << "main is " << getpid() << endl;
+
+ // Acceptor factory.
+ Logging_Acceptor peer_acceptor;
+
+ if (peer_acceptor.open (ACE_INET_Addr (PORT)) == -1)
+ ACE_ERROR_RETURN ((LM_ERROR, "%p\n", "open"), -1);
+
+ else if (g_reactor->register_handler (&peer_acceptor, ACE_Event_Handler::READ_MASK) == -1)
+ ACE_ERROR_RETURN ((LM_ERROR, "registering service with ACE_Reactor\n"), -1);
+
+ ACE_Sig_Action sa ((ACE_SignalHandler) handler, SIGINT);
+
+ // Run forever, performing logging service.
+
+ ACE_DEBUG ((LM_DEBUG, "(%P|%t) starting up server logging daemon\n"));
+
+ // Perform logging service until QUIT_HANDLER receives SIGINT.
+ while ( !finished )
+ g_reactor->handle_events ();
+
+ ACE_DEBUG ((LM_DEBUG, "(%P|%t) shutting down server logging daemon\n"));
+
+ return 0;
+}
diff --git a/docs/tutorials/005a/server.cpp b/docs/tutorials/005a/server.cpp
new file mode 100644
index 00000000000..70b92716f02
--- /dev/null
+++ b/docs/tutorials/005a/server.cpp
@@ -0,0 +1,145 @@
+// $Id$
+
+#include "ace/Acceptor.h"
+#include "ace/SOCK_Acceptor.h"
+#include "ace/Reactor.h"
+#include "ace/Thread.h"
+
+
+ACE_Reactor * g_reactor;
+
+static sig_atomic_t finished = 0;
+
+
+extern "C" void handler (int) { finished = 1; }
+static void *thread_run(void *);
+// ----------------------------------------
+
+class Logging_Handler : public ACE_Svc_Handler<ACE_SOCK_STREAM, ACE_NULL_SYNCH>
+{
+
+public:
+
+ Logging_Handler (void)
+ {
+ thread_reactor = NULL;
+ }
+
+ ~Logging_Handler (void)
+ {
+ cout << "in destructor" <<endl;
+ delete thread_reactor;
+ }
+
+ virtual void destroy (void)
+ {
+ cout << " in destroy" <<endl;
+ g_reactor->cancel_timer (this);
+ this->peer ().close ();
+ delete this;
+ }
+
+ static void *run_thread(Logging_Handler *this_)
+ {
+ cout << "run_thread in " << getpid() << endl;
+
+ this_->thread_reactor = new ACE_Reactor;
+
+ if (this_->thread_reactor->register_handler(this_, ACE_Event_Handler::READ_MASK) == -1)
+ ACE_ERROR_RETURN ((LM_ERROR,"can'(%P|%t) t register with reactor\n"), -1);
+ else if (this_->thread_reactor->schedule_timer (this_, (const void *)this_, ACE_Time_Value (2), ACE_Time_Value (2)) == -1)
+ ACE_ERROR_RETURN ((LM_ERROR, "can'(%P|%t) t register with reactor\n"), -1);
+ else
+ ACE_DEBUG ((LM_DEBUG, "(%P|%t) connected with client \n"));
+
+ while(!finished)
+ this_->thread_reactor->handle_events();
+
+ }
+
+ virtual int open (void *)
+ {
+ ACE_Thread::spawn(&Logging_Handler::run_thread,this);
+ return 0;
+ }
+
+ virtual int close (u_long)
+ {
+
+ if (this->thread_reactor->remove_handler(this,ACE_Event_Handler::READ_MASK | ACE_Event_Handler::DONT_CALL) == -1)
+ ACE_ERROR_RETURN ((LM_ERROR, "can'(%P|%t) t remove service from reactor\n"), -1);
+ this->destroy ();
+ return 0;
+ }
+
+protected:
+
+ virtual int handle_input (ACE_HANDLE)
+ {
+ char buf[128];
+ memset(buf,0,sizeof(buf));
+
+ cout << "handle_input in " << getpid() << endl;
+ switch( this->peer().recv(buf,sizeof buf) )
+ {
+ case -1:
+ ACE_ERROR_RETURN ((LM_ERROR, "(%P|%t) %p bad read\n", "client logger"), -1);
+ case 0:
+ ACE_ERROR_RETURN ((LM_ERROR, "(%P|%t) closing log daemon (fd = %d)\n", this->get_handle ()), -1);
+ default:
+ cout << "Data from client " << buf << endl;
+ // ACE_DEBUG ((LM_DEBUG, "(%P|%t) from client: %s",buf));
+ }
+
+ return 0;
+ }
+
+ virtual int handle_timeout (const ACE_Time_Value &tv, const void *arg)
+ {
+ ACE_ASSERT (arg == this);
+ // ACE_DEBUG ((LM_DEBUG, "(%P|%t) handling timeout from this = %u\n", this));
+ cout << "Timout in " << getpid() << endl;
+ return 0;
+ }
+
+private:
+ ACE_Reactor *thread_reactor;
+ char peer_name_[MAXHOSTNAMELEN + 1];
+
+};
+
+
+typedef ACE_Acceptor <Logging_Handler, ACE_SOCK_ACCEPTOR> Logging_Acceptor;
+
+
+static const u_short PORT = ACE_DEFAULT_SERVER_PORT;
+
+int main (int argc, char *argv[])
+{
+ g_reactor = new ACE_Reactor;
+
+ cout << "main is " << getpid() << endl;
+
+ // Acceptor factory.
+ Logging_Acceptor peer_acceptor;
+
+ if (peer_acceptor.open (ACE_INET_Addr (PORT)) == -1)
+ ACE_ERROR_RETURN ((LM_ERROR, "%p\n", "open"), -1);
+
+ else if (g_reactor->register_handler (&peer_acceptor, ACE_Event_Handler::READ_MASK) == -1)
+ ACE_ERROR_RETURN ((LM_ERROR, "registering service with ACE_Reactor\n"), -1);
+
+ ACE_Sig_Action sa ((ACE_SignalHandler) handler, SIGINT);
+
+ // Run forever, performing logging service.
+
+ ACE_DEBUG ((LM_DEBUG, "(%P|%t) starting up server logging daemon\n"));
+
+ // Perform logging service until QUIT_HANDLER receives SIGINT.
+ while ( !finished )
+ g_reactor->handle_events ();
+
+ ACE_DEBUG ((LM_DEBUG, "(%P|%t) shutting down server logging daemon\n"));
+
+ return 0;
+}
diff --git a/docs/tutorials/005a/server.dyn b/docs/tutorials/005a/server.dyn
new file mode 100644
index 00000000000..1baceaf64f5
--- /dev/null
+++ b/docs/tutorials/005a/server.dyn
@@ -0,0 +1,144 @@
+
+1. #include "ace/Acceptor.h"
+2. #include "ace/SOCK_Acceptor.h"
+3. #include "ace/Reactor.h"
+4. #include "ace/Thread.h"
+
+
+5. ACE_Reactor * g_reactor;
+
+6. static sig_atomic_t finished = 0;
+
+
+7. extern "C" void handler (int) { finished = 1; }
+8. static void *thread_run(void *);
+ // ----------------------------------------
+
+9. class Logging_Handler : public ACE_Svc_Handler<ACE_SOCK_STREAM, ACE_NULL_SYNCH>
+ {
+
+ public:
+
+10. Logging_Handler (void)
+ {
+11. thread_reactor = NULL;
+ }
+
+12. ~Logging_Handler (void)
+ {
+13. cout << "in destructor" <<endl;
+14. delete thread_reactor;
+ }
+
+15. virtual void destroy (void)
+ {
+16. cout << " in destroy" <<endl;
+17. g_reactor->cancel_timer (this);
+18. this->peer ().close ();
+19. delete this;
+ }
+
+20. static void *run_thread(Logging_Handler *this_)
+ {
+21. cout << "run_thread in " << getpid() << endl;
+
+22. this_->thread_reactor = new ACE_Reactor;
+
+23. if (this_->thread_reactor->register_handler(this_, ACE_Event_Handler::READ_MASK) == -1)
+24. ACE_ERROR_RETURN ((LM_ERROR,"can'(%P|%t) t register with reactor\n"), -1);
+25. else if (this_->thread_reactor->schedule_timer (this_, (const void *)this_, ACE_Time_Value (2), ACE_Time_Value (2)) == -1)
+26. ACE_ERROR_RETURN ((LM_ERROR, "can'(%P|%t) t register with reactor\n"), -1);
+27. else
+28. ACE_DEBUG ((LM_DEBUG, "(%P|%t) connected with client \n"));
+
+29. while(!finished)
+30. this_->thread_reactor->handle_events();
+
+ }
+
+31. virtual int open (void *)
+ {
+32. ACE_Thread::spawn(&Logging_Handler::run_thread,this);
+33. return 0;
+ }
+
+34. virtual int close (u_long)
+ {
+
+35. if (this->thread_reactor->remove_handler(this,ACE_Event_Handler::READ_MASK | ACE_Event_Handler::DONT_CALL) == -1)
+36. ACE_ERROR_RETURN ((LM_ERROR, "can'(%P|%t) t remove service from reactor\n"), -1);
+37. this->destroy ();
+38. return 0;
+ }
+
+ protected:
+
+39. virtual int handle_input (ACE_HANDLE)
+ {
+40. char buf[128];
+41. memset(buf,0,sizeof(buf));
+
+42. cout << "handle_input in " << getpid() << endl;
+43. switch( this->peer().recv(buf,sizeof buf) )
+ {
+44. case -1:
+45. ACE_ERROR_RETURN ((LM_ERROR, "(%P|%t) %p bad read\n", "client logger"), -1);
+46. case 0:
+47. ACE_ERROR_RETURN ((LM_ERROR, "(%P|%t) closing log daemon (fd = %d)\n", this->get_handle ()), -1);
+48. default:
+49. cout << "Data from client " << buf << endl;
+ // ACE_DEBUG ((LM_DEBUG, "(%P|%t) from client: %s",buf));
+ }
+
+50. return 0;
+ }
+
+51. virtual int handle_timeout (const ACE_Time_Value &tv, const void *arg)
+ {
+52. ACE_ASSERT (arg == this);
+ // ACE_DEBUG ((LM_DEBUG, "(%P|%t) handling timeout from this = %u\n", this));
+53. cout << "Timout in " << getpid() << endl;
+54. return 0;
+ }
+
+ private:
+55. ACE_Reactor *thread_reactor;
+56. char peer_name_[MAXHOSTNAMELEN + 1];
+
+ };
+
+
+57. typedef ACE_Acceptor <Logging_Handler, ACE_SOCK_ACCEPTOR> Logging_Acceptor;
+
+
+58. static const u_short PORT = ACE_DEFAULT_SERVER_PORT;
+
+59. int main (int argc, char *argv[])
+ {
+60. g_reactor = new ACE_Reactor;
+
+61. cout << "main is " << getpid() << endl;
+
+ // Acceptor factory.
+62. Logging_Acceptor peer_acceptor;
+
+63. if (peer_acceptor.open (ACE_INET_Addr (PORT)) == -1)
+64. ACE_ERROR_RETURN ((LM_ERROR, "%p\n", "open"), -1);
+
+65. else if (g_reactor->register_handler (&peer_acceptor, ACE_Event_Handler::READ_MASK) == -1)
+66. ACE_ERROR_RETURN ((LM_ERROR, "registering service with ACE_Reactor\n"), -1);
+
+67. ACE_Sig_Action sa ((ACE_SignalHandler) handler, SIGINT);
+
+ // Run forever, performing logging service.
+
+68. ACE_DEBUG ((LM_DEBUG, "(%P|%t) starting up server logging daemon\n"));
+
+ // Perform logging service until QUIT_HANDLER receives SIGINT.
+69. while ( !finished )
+70. g_reactor->handle_events ();
+
+71. ACE_DEBUG ((LM_DEBUG, "(%P|%t) shutting down server logging daemon\n"));
+
+72. return 0;
+ }
diff --git a/docs/tutorials/005a/server.news b/docs/tutorials/005a/server.news
new file mode 100644
index 00000000000..51db8033c36
--- /dev/null
+++ b/docs/tutorials/005a/server.news
@@ -0,0 +1,139 @@
+
+#include "ace/Acceptor.h"
+#include "ace/SOCK_Acceptor.h"
+#include "ace/Reactor.h"
+#include "ace/Thread.h"
+
+
+ACE_Reactor * g_reactor;
+
+static sig_atomic_t finished = 0;
+
+
+extern "C" void handler (int) { finished = 1; }
+static void *thread_run(void *);
+// ----------------------------------------
+
+class Logging_Handler : public ACE_Svc_Handler<ACE_SOCK_STREAM, ACE_NULL_SYNCH>
+{
+
+public:
+
+ Logging_Handler (void)
+ {
+ thread_reactor = NULL;
+ }
+
+ ~Logging_Handler (void)
+ {
+ delete thread_reactor;
+ }
+
+ virtual void destroy (void)
+ {
+ g_reactor->cancel_timer (this);
+ this->peer ().close ();
+ delete this;
+ }
+
+ static void *run_thread(Logging_Handler *this_)
+ {
+ cout << "run_thread in " << getpid() << endl;
+
+ this_->thread_reactor = new ACE_Reactor;
+
+ if (this_->thread_reactor->register_handler(this_, ACE_Event_Handler::READ_MASK) == -1)
+ ACE_ERROR_RETURN ((LM_ERROR, "(%P|%t) can't register with reactor\n"), -1);
+ else if (this_->thread_reactor->schedule_timer (this_, (const void *)this_, ACE_Time_Value (2), ACE_Time_Value (2)) == -1)
+ ACE_ERROR_RETURN ((LM_ERROR, "can'(%P|%t) t register with reactor\n"), -1);
+ else
+ ACE_DEBUG ((LM_DEBUG, "(%P|%t) connected with client \n"));
+
+ while(!finished)
+ this_->thread_reactor->handle_events();
+
+ }
+
+ virtual int open (void *)
+ {
+ ACE_Thread::spawn(&Logging_Handler::run_thread,this);
+ return 0;
+ }
+
+ virtual int close (u_long)
+ {
+ this->destroy ();
+ return 0;
+ }
+
+protected:
+
+ virtual int handle_input (ACE_HANDLE)
+ {
+ char buf[128];
+ memset(buf,0,sizeof(buf));
+
+ cout << "handle_input in " << getpid() << endl;
+ switch( this->peer().recv(buf,sizeof buf) )
+ {
+ case -1:
+ ACE_ERROR_RETURN ((LM_ERROR, "(%P|%t) %p bad read\n", "client logger"), -1);
+ case 0:
+ ACE_ERROR_RETURN ((LM_ERROR, "(%P|%t) closing log daemon (fd = %d)\n", this->get_handle ()), -1);
+ default:
+ cout << "Data from client " << buf << endl;
+ // ACE_DEBUG ((LM_DEBUG, "(%P|%t) from client: %s",buf));
+ }
+
+ return 0;
+ }
+
+ virtual int handle_timeout (const ACE_Time_Value &tv, const void *arg)
+ {
+ ACE_ASSERT (arg == this);
+ // ACE_DEBUG ((LM_DEBUG, "(%P|%t) handling timeout from this = %u\n", this));
+ cout << "Timout in " << getpid() << endl;
+ return 0;
+ }
+
+private:
+ ACE_Reactor *thread_reactor;
+ char peer_name_[MAXHOSTNAMELEN + 1];
+
+};
+
+
+typedef ACE_Acceptor <Logging_Handler, ACE_SOCK_ACCEPTOR> Logging_Acceptor;
+
+
+static const u_short PORT = ACE_DEFAULT_SERVER_PORT;
+
+int main (int argc, char *argv[])
+{
+ g_reactor = new ACE_Reactor;
+
+ cout << "main is " << getpid() << endl;
+
+ // Acceptor factory.
+ Logging_Acceptor peer_acceptor;
+
+ if (peer_acceptor.open (ACE_INET_Addr (PORT)) == -1)
+ ACE_ERROR_RETURN ((LM_ERROR, "%p\n", "open"), -1);
+
+ else if (g_reactor->register_handler (&peer_acceptor, ACE_Event_Handler::READ_MASK) == -1)
+ ACE_ERROR_RETURN ((LM_ERROR, "registering service with ACE_Reactor\n"), -1);
+
+ ACE_Sig_Action sa ((ACE_SignalHandler) handler, SIGINT);
+
+ // Run forever, performing logging service.
+
+ ACE_DEBUG ((LM_DEBUG, "(%P|%t) starting up server logging daemon\n"));
+
+ // Perform logging service until QUIT_HANDLER receives SIGINT.
+ while ( !finished )
+ g_reactor->handle_events ();
+
+ ACE_DEBUG ((LM_DEBUG, "(%P|%t) shutting down server logging daemon\n"));
+
+ return 0;
+}
diff --git a/docs/tutorials/005a/serverBroken b/docs/tutorials/005a/serverBroken
new file mode 100644
index 00000000000..21c4f5f8e7d
--- /dev/null
+++ b/docs/tutorials/005a/serverBroken
Binary files differ
diff --git a/docs/tutorials/005a/serverBroken.cpp b/docs/tutorials/005a/serverBroken.cpp
new file mode 100644
index 00000000000..09f446483c0
--- /dev/null
+++ b/docs/tutorials/005a/serverBroken.cpp
@@ -0,0 +1,143 @@
+// $Id$
+
+#include "ace/Acceptor.h"
+#include "ace/SOCK_Acceptor.h"
+#include "ace/Reactor.h"
+#include "ace/Thread.h"
+
+ACE_Reactor * g_reactor;
+
+static sig_atomic_t finished = 0;
+
+extern "C" void handler (int) { finished = 1; }
+static void *thread_run(void *);
+// ----------------------------------------
+
+class Logging_Handler : public ACE_Svc_Handler<ACE_SOCK_STREAM, ACE_NULL_SYNCH>
+{
+
+public:
+
+ Logging_Handler (void)
+ {
+ thread_reactor = NULL;
+ }
+
+ ~Logging_Handler (void)
+ {
+ cout << "in destructor";
+ delete thread_reactor;
+ }
+
+ virtual void destroy (void)
+ {
+ cout << " in destroy";
+ g_reactor->cancel_timer (this);
+ this->peer ().close ();
+ delete this;
+ }
+
+ static void *run_thread(Logging_Handler *this_)
+ {
+ cout << "run_thread in " << getpid() << endl;
+
+ this_->thread_reactor = new ACE_Reactor;
+
+ if (this_->thread_reactor->register_handler(this_, ACE_Event_Handler::READ_MASK) == -1)
+ ACE_ERROR_RETURN ((LM_ERROR,"can'(%P|%t) t register with reactor\n"), -1);
+ else if (this_->thread_reactor->schedule_timer (this_, (const void *)this_, ACE_Time_Value (2), ACE_Time_Value (2)) == -1)
+ ACE_ERROR_RETURN ((LM_ERROR, "can'(%P|%t) t register with reactor\n"), -1);
+ else
+ ACE_DEBUG ((LM_DEBUG, "(%P|%t) connected with client \n"));
+
+ while(!finished)
+ this_->thread_reactor->handle_events();
+
+ }
+
+ virtual int open (void *)
+ {
+ ACE_Thread::spawn(&Logging_Handler::run_thread,this);
+ return 0;
+ }
+
+ virtual int close (u_long)
+ {
+
+ if (this->thread_reactor->remove_handler(this,ACE_Event_Handler::READ_MASK) == -1)
+ ACE_ERROR_RETURN ((LM_ERROR, "can'(%P|%t) t remove service from reactor\n"), -1);
+ this->destroy ();
+ return 0;
+ }
+
+protected:
+
+ virtual int handle_input (ACE_HANDLE)
+ {
+ char buf[128];
+ memset(buf,0,sizeof(buf));
+
+ cout << "handle_input in " << getpid() << endl;
+ switch( this->peer().recv(buf,sizeof buf) )
+ {
+ case -1:
+ ACE_ERROR_RETURN ((LM_ERROR, "(%P|%t) %p bad read\n", "client logger"), -1);
+ case 0:
+ ACE_ERROR_RETURN ((LM_ERROR, "(%P|%t) closing log daemon (fd = %d)\n", this->get_handle ()), -1);
+ default:
+ cout << "Data from client " << buf << endl;
+ // ACE_DEBUG ((LM_DEBUG, "(%P|%t) from client: %s",buf));
+ }
+
+ return 0;
+ }
+
+ virtual int handle_timeout (const ACE_Time_Value &tv, const void *arg)
+ {
+ ACE_ASSERT (arg == this);
+ // ACE_DEBUG ((LM_DEBUG, "(%P|%t) handling timeout from this = %u\n", this));
+ cout << "Timout in " << getpid() << endl;
+ return 0;
+ }
+
+private:
+ ACE_Reactor *thread_reactor;
+ char peer_name_[MAXHOSTNAMELEN + 1];
+
+};
+
+
+typedef ACE_Acceptor <Logging_Handler, ACE_SOCK_ACCEPTOR> Logging_Acceptor;
+
+
+static const u_short PORT = ACE_DEFAULT_SERVER_PORT;
+
+int main (int argc, char *argv[])
+{
+ g_reactor = new ACE_Reactor;
+
+ cout << "main is " << getpid() << endl;
+
+ // Acceptor factory.
+ Logging_Acceptor peer_acceptor;
+
+ if (peer_acceptor.open (ACE_INET_Addr (PORT)) == -1)
+ ACE_ERROR_RETURN ((LM_ERROR, "%p\n", "open"), -1);
+
+ else if (g_reactor->register_handler (&peer_acceptor, ACE_Event_Handler::READ_MASK) == -1)
+ ACE_ERROR_RETURN ((LM_ERROR, "registering service with ACE_Reactor\n"), -1);
+
+ ACE_Sig_Action sa ((ACE_SignalHandler) handler, SIGINT);
+
+ // Run forever, performing logging service.
+
+ ACE_DEBUG ((LM_DEBUG, "(%P|%t) starting up server logging daemon\n"));
+
+ // Perform logging service until QUIT_HANDLER receives SIGINT.
+ while ( !finished )
+ g_reactor->handle_events ();
+
+ ACE_DEBUG ((LM_DEBUG, "(%P|%t) shutting down server logging daemon\n"));
+
+ return 0;
+}
diff --git a/docs/tutorials/006/Makefile b/docs/tutorials/006/Makefile
new file mode 100644
index 00000000000..22fbdcce08a
--- /dev/null
+++ b/docs/tutorials/006/Makefile
@@ -0,0 +1,42 @@
+#----------------------------------------------------------------------------
+# $Id$
+#
+# Makefile for the Reactor version of the Server Logging Daemon
+#----------------------------------------------------------------------------
+
+#----------------------------------------------------------------------------
+# Local macros
+#----------------------------------------------------------------------------
+
+BIN = notify server
+
+VLDLIBS = $(LDLIBS:%=%$(VAR))
+
+BUILD = $(VBIN)
+
+#----------------------------------------------------------------------------
+# Include macros and targets
+#----------------------------------------------------------------------------
+
+include $(WRAPPER_ROOT)/include/makeinclude/wrapper_macros.GNU
+include $(WRAPPER_ROOT)/include/makeinclude/macros.GNU
+include $(WRAPPER_ROOT)/include/makeinclude/rules.common.GNU
+include $(WRAPPER_ROOT)/include/makeinclude/rules.nonested.GNU
+include $(WRAPPER_ROOT)/include/makeinclude/rules.lib.GNU
+include $(WRAPPER_ROOT)/include/makeinclude/rules.bin.GNU
+include $(WRAPPER_ROOT)/include/makeinclude/rules.local.GNU
+
+#----------------------------------------------------------------------------
+# Local targets
+#----------------------------------------------------------------------------
+
+#----------------------------------------------------------------------------
+# Dependencies
+#----------------------------------------------------------------------------
+
+# DO NOT DELETE THIS LINE -- g++dep uses it.
+# DO NOT PUT ANYTHING AFTER THIS LINE, IT WILL GO AWAY.
+
+
+
+# IF YOU PUT ANYTHING HERE IT WILL GO AWAY
diff --git a/docs/tutorials/006/ideas01 b/docs/tutorials/006/ideas01
new file mode 100644
index 00000000000..e973d19519c
--- /dev/null
+++ b/docs/tutorials/006/ideas01
@@ -0,0 +1,100 @@
+
+
+class ADS_Thread_Reactor : public ACE_Reactor {
+private:
+ ThreadSafeList<ADS_Connection_Handler> connectionList;
+ ThreadSafeList<ADS_Connection_Handler> pendingConnectionList;
+ uint svcHandlerCount;
+ statistics-information-variables;
+public:
+ ADS_Thread_Reactor(void);
+ Boolean ConnectionListIsEmpty(void); // return TRUE if connectionList has no entries
+ ADS_Thread_Reactor * LocateIdleReactor(void); // locate a reactor that isn't too busy for another connection
+ void RegisterNewConnections(void); // call register_handler on everything in pendingConnectionList
+ reactor.AdjustStatistics( ulong, Time ); // accumulate some kind of "busy" indication statistics
+};
+
+ADS_Thread_Reactor(void) : () {
+ svcHandlerCount = 0;
+ connectionList.MakeEmpty();
+}
+
+typedef ACE_Singleton<ADS_Thread_Reactor> ADS_ReactorSingleton; // Added 1/18
+
+ADS_Connection_Handler is very similar to Doug's soultion but with additions.
+
+/*
+ * The open method is called by the Acceptor when a new connection is accepted.
+ * It needs access to the reactor which is handling the acceptor. That may be a problem.
+ * It tries to locate a thread-pool reactor to handle the new connection (itself).
+ * If none can be found, it will activate itself to become a new thread-pool reactor loop.
+ * If one is found, the connection places itself in that thread-pool reactor's list of pending connections.
+ */
+open(...) {
+ // ADS_Thread_Reactor * r = this->reactor(); // Replaced 1/18
+ ADS_Thread_Reactor * r = ADS_ReactorSingleton::instance(); // Added 1/18
+ ADS_Thread_Reactor * tr;
+
+ if( r->ConnectionListIsEmpty() || !(tr = r->LocateIdleReactor()) ) {
+ this->activate();
+ } else {
+ /*
+ * Tell the acceptor's reactor to add us to the list of connection_handlers
+ * which are executing a reactor loop and willing to handle more connections.
+ */
+ r->AddToConnectionList(this);
+ tr->Enque(this);
+ }
+}
+
+
+
+svc(...) {
+ ADS_Thread_Reactor reactor;
+ /*
+ * We have to create a new connection object to handle the actual connection
+ * because we are going to become the reactor's event loop. If we were to
+ * register ourselves with the reactor then we would delete ourself when the
+ * connection ended. That would be very bad because when the thread invoking
+ * svc() exits, it will call the svc() object's close() method (us, in other words). Now
+ * you're calling a member function of a deleted object. Very bad.
+ *
+ * To avoid all of that, we create a new connection object initialized with ourselves
+ * and feed it to the reactor to deal with the data stream. It can safely delete itself
+ * when the connection closes and we can delete ourself when the thread exits and
+ * all will be just fine.
+ */
+ ADS_Connection_Handler connection(this);
+
+ ulong loopCount = 0;
+
+ reactor.register_handler( connection, ... );
+
+ while( reactor.HandleCount() > 0 )
+ {
+ Time tStart = now(); // Get the current time
+
+ reactor.handle_events( some-timeout? ); // typical reactor loop stuff
+
+ reactor.RegisterNewConnections();
+
+ reactor.AdjustStatistics( loopCount++, now - tStart );
+ }
+}
+
+
+
+Q: Does a Svc_Handler have access to the reactor it's handler is registered with?
+
+How about using a reactor singleton for the acceptor. Then, the other threads have
+access to it by using ADS_ReactorSingleton::instance(). When the acceptor object is
+created it would be registered with the singleton. We need a wrapper class that hides
+the details of acceptor creation, configuration and registration anyway. (On the
+client side, we need a wrapper for connection creation, etc... as well.)
+
+
+
+When examining the ThreadSafeList<> objects, we should use a ReadersWriter
+lock to speed things up. We only need a mutex when writting new data to them.
+
+
diff --git a/docs/tutorials/006/index.html b/docs/tutorials/006/index.html
new file mode 100644
index 00000000000..14d38a237ea
--- /dev/null
+++ b/docs/tutorials/006/index.html
@@ -0,0 +1,104 @@
+<HTML>
+<HEAD>
+ <TITLE>ACE Tutorial 006</TITLE>
+</HEAD>
+<BODY text = "#000000" link="#000fff" vlink="#ff0f0f" bgcolor="#ffffff">
+
+
+<CENTER><P><B><FONT SIZE=+2>ACE&nbsp;Tutorial 006<BR>
+Creating a Thread Pool Server with Multiple Reactors</FONT></B></P></CENTER>
+
+<P>
+<HR WIDTH="100%">
+
+<P>
+In <A HREF="../005/page01.html">Tutorial 5</A> we learned how to create
+a multi-threaded server. In that exercise, as each connection request
+was accepted, a new thread with a dedicated reactor was created to
+process the connection. This is basically the <I>thread per request</I>
+modle that is modified to use a reactor instead of traditional read-blocking.
+<P>
+To more effectively use the reactor's functionality and more efficently
+use the systems' resources it makes sense for each thread in our pool
+to accomodate multiple connections instead of just one. Prior to implementing
+this goal, we must first answer several questions:
+<UL>
+<LI>How will the acceptor pass a new connection to a handler thread?
+<LI>In passing the connection to a handler thread, how will the acceptor
+"interrupt" the handler thread's reactor?
+<LI>How will the acceptor thread choose the appropriate handler thread?
+<LI>What kind of global (ie -- singleton) data structures will be
+needed to keep track of active connections and handler threads?
+</UL>
+
+<P>
+This is not, of course, the complete list of questions that will arise
+as this tutorial progresses in its development. As new questions are
+asked, they will be listed here even if the answer is not yet known.
+This ensures that we will cover all of the bases before we're done.
+
+<P>
+In order to answer these questions, we will build this tutorial
+in a different way than the previous tutorials. The reader will be
+shown a series of short, typically one or two page, tutorials that
+will build towards the final solution.
+
+<P>
+<UL>
+<LI><A HREF="page01.html">How do message queues work?</A><br>
+<!-- Note... if "page01.html" spills over to multiple pages,
+ we should go with "page01a.html", etc.. instead of going
+ to "page02.html". That let's us reserve the 01, 02, etc
+ for the start-point of each sub-tutorial.
+--!>
+ACE message queues will form the backbone of the communication
+between our threads. With this tool, the acceptor thread will
+be able to inform the handler thread of new connetions. Later,
+when we begin expanding our search into distributed objects,
+we will use a similar mechanism for an "application" thread
+to pass data to a "connection" thread for transmission to a
+remote process.
+<P>
+<LI><A HREF="page02.html">How can you interrupt a reactor?</A><br>
+Once we know how to use a message queue we will be wanting to
+use it to pass data from one connection thread (probably the
+acceptor thread) to another. Since each connection thread will
+have a reactor, we need a reliable way to "interrupt" that reactor
+so that the message queue will be read.
+In this sub-section, we use an example which allows the
+program's main thread to send data to each of the connection
+threads. We also begin to investigate ways of keeping track
+of the various connection threads.
+<P>
+</UL>
+
+<P>
+
+<HR>
+
+<P>
+Some terms used above and throughout this tutorial:
+<DL>
+<DT>acceptor thread
+<DD>The <I>acceptor thread</I> is the program's thread of execution
+which contains a reactor loop managing the reactor to which the program's
+acceptor has been registered. Any new connection requests will be seen
+by this thread initially.
+<DT>handler thread
+<DD>Each of the threads in the pool will contain a reactor. The actual
+connection service handlers will be registered with these reactors.
+The <I>acceptor thread</I> may have connection service handlers registered
+with it as well, but that is not recommended at this point.
+<DT>application thread
+<DD>This is a broad term which I use to refer to the primary thread
+of an application. Typically, the application programmer will maintain
+control of this thread and not be aware of the IPC-generated threads
+at all.
+<DT>connection thread
+<DD>A generic term I use to describe either an acceptor thread or
+handler thread. In some simple clients, there may be only one thread
+handling both functions.
+</DL>
+<hr>
+<CENTER><P>[<A HREF="../../Tutorial">Tutorial Index</A>]
+</center>
diff --git a/docs/tutorials/006/notify b/docs/tutorials/006/notify
new file mode 100644
index 00000000000..10098b9dabf
--- /dev/null
+++ b/docs/tutorials/006/notify
Binary files differ
diff --git a/docs/tutorials/006/notify.cpp b/docs/tutorials/006/notify.cpp
new file mode 100644
index 00000000000..d38fe8868b0
--- /dev/null
+++ b/docs/tutorials/006/notify.cpp
@@ -0,0 +1,199 @@
+// $Id$
+
+#include "ace/Reactor.h"
+#include "ace/Thread.h"
+#include "ace/Message_Queue.h"
+
+typedef ACE_Message_Queue<ACE_MT_SYNCH> Message_Queue;
+
+////////////////////////////////////////////////////////////////////////////////
+
+class IPCQueue : public Message_Queue
+{
+protected:
+ ACE_Event_Handler * event_handler_;
+ ACE_Reactor * reactor_;
+public:
+ IPCQueue( )
+ {
+ event_handler_ = NULL;
+ reactor_ = NULL;
+ }
+
+ void configure( ACE_Reactor * reactor, ACE_Event_Handler * handler )
+ {
+ reactor_ = reactor;
+ event_handler_ = handler;
+ }
+
+ virtual int notify(void)
+ {
+ if( reactor_ && event_handler_ )
+ this->reactor_->notify( event_handler_, ACE_Event_Handler::WRITE_MASK);
+
+ return 0;
+ }
+
+ int dequeue( ACE_Message_Block * & message_block )
+ {
+ ACE_Time_Value timeout(ACE_OS::time(0)+1,0);
+
+ return dequeue_head(message_block,&timeout) ;
+ }
+};
+
+////////////////////////////////////////////////////////////////////////////////
+
+class FoobarBase
+{
+protected:
+ IPCQueue data_queue_;
+ ACE_Thread_Manager & thr_mgr_;
+
+public:
+ FoobarBase( ACE_Thread_Manager & _thr_mgr ) : data_queue_ (), thr_mgr_ (_thr_mgr)
+ {
+ }
+
+ ACE_Thread_Manager & thr_mgr(void)
+ {
+ return thr_mgr_;
+ }
+
+ IPCQueue & queue()
+ {
+ return data_queue_;
+ }
+};
+
+////////////////////////////////////////////////////////////////////////////////
+
+class Foobar : public FoobarBase
+{
+public:
+ Foobar( ACE_Thread_Manager & _thr_mgr ) : FoobarBase(_thr_mgr)
+ {
+ }
+
+ void produce_data( char * buf )
+ {
+ ACE_Message_Block *message_block =
+ new ACE_Message_Block( strlen(buf), ACE_Message_Block::MB_DATA, 0, buf );
+
+ data_queue_.enqueue_tail(message_block);
+
+ return;
+ }
+
+ void consume_data( char * buf )
+ {
+
+ if( buf )
+ cerr << ACE_Thread::self() << " Consuming (" << buf << ") " << (void *)buf << endl;
+
+ return;
+ }
+};
+
+////////////////////////////////////////////////////////////////////////////////
+
+template <class OBJ>
+class FoobarHandler : public ACE_Event_Handler
+{
+protected:
+ OBJ * foobar_;
+
+public:
+ FoobarHandler(OBJ * _foobar, ACE_Reactor * reactor)
+ {
+ foobar_ = _foobar;
+
+ reactor->register_handler( this, ACE_Event_Handler::READ_MASK );
+ this->reactor(reactor);
+
+ foobar_->queue().configure( reactor, this );
+ }
+
+ virtual int handle_timeout (const ACE_Time_Value & tv, const void *arg = 0)
+ {
+ cerr << ACE_Thread::self() << " Timeout" << endl;
+
+ this->reactor()->notify( this, ACE_Event_Handler::WRITE_MASK);
+
+ return 0;
+ }
+
+ virtual int handle_output (ACE_HANDLE)
+ {
+ ACE_Message_Block * block = NULL;
+
+ if( foobar_->queue().dequeue(block) != -1 )
+ {
+ foobar_->consume_data( block->base() );
+ delete block;
+ }
+ else
+ {
+ cerr << ACE_Thread::self() << " Nothing in queue" << endl;
+ }
+
+ return 0;
+ }
+};
+
+////////////////////////////////////////////////////////////////////////////////
+
+static void *thread_func(void * arg1)
+{
+ Foobar * foobar = (Foobar *)arg1;
+
+ ACE_Thread_Control thread_control ( & foobar->thr_mgr() );
+
+ ACE_Reactor reactor;
+
+ FoobarHandler<Foobar> handler(foobar,&reactor);
+
+ if (reactor.schedule_timer (&handler, 0, ACE_Time_Value (1, 0), ACE_Time_Value (0, 3500000)) == -1)
+ ACE_ERROR_RETURN ((LM_ERROR, "ACE_Reactor::schedule_timer"), -1);
+
+ for( int i = 0 ; i < 50 ; ++i )
+ {
+ cerr << ACE_Thread::self() << " " << i << endl;
+ reactor.handle_events( ACE_Time_Value(5,0 ) );
+ }
+
+ return 0;
+}
+
+////////////////////////////////////////////////////////////////////////////////
+
+main()
+{
+ ACE_Thread_Manager thr_mgr;
+
+ cerr << ACE_Thread::self() << " Main Thread" << endl;
+
+ Foobar foobar(thr_mgr);
+
+ if (thr_mgr.spawn(ACE_THR_FUNC (thread_func),&foobar,THR_NEW_LWP | THR_DETACHED) == -1)
+ ACE_ERROR_RETURN((LM_ERROR,"%p\n","spawing client thread"),1);
+
+ sleep(1);
+
+ for( int i = 0 ; i < 10 ; ++i )
+ {
+ char buf[64];
+ sprintf(buf,"This is iteration %d",i);
+
+ foobar.produce_data(buf);
+
+ sleep(2);
+ }
+
+ thr_mgr.wait();
+
+ exit(0);
+}
+
+////////////////////////////////////////////////////////////////////////////////
+
diff --git a/docs/tutorials/006/page01.html b/docs/tutorials/006/page01.html
new file mode 100644
index 00000000000..4f97845613b
--- /dev/null
+++ b/docs/tutorials/006/page01.html
@@ -0,0 +1,234 @@
+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 3.2//EN">
+<HTML>
+<HEAD>
+ <TITLE>ACE Tutorial 001</TITLE>
+ <META NAME="GENERATOR" CONTENT="Mozilla/3.0Gold (Win95; I) [Netscape]">
+ <META NAME="Author" CONTENT="James CE Johnson">
+ <META NAME="Description" CONTENT="A first step towards using ACE productively">
+</HEAD>
+<BODY text = "#000000" link="#000fff" vlink="#ff0f0f" bgcolor="#ffffff">
+
+
+<CENTER><P><B><FONT SIZE=+2>ACE&nbsp;Tutorial 006<BR>
+Creating a Thread Pool Server</FONT></B></P></CENTER>
+
+<P>
+<HR WIDTH="100%"></P>
+
+<P>As a build up to our final thread pool server , we will examine a number
+of specific topics that will be integrated to form the final product. In
+this section of the tutorial I will expose message queues, specifically
+the <I>ACE_Message_Queue</I> wrapper class that hides the low level details
+of building and manipulating a message queue. As in previous tutorials,
+I will display the appropriate source code, however, I will explain the
+code in sections rather than a line by line introduction. </P>
+
+<P>We begin by looking at a sample message queue program:</P>
+
+<UL>
+<PRE>
+1. #include &quot;ace/Thread.h&quot;
+2. #include &quot;ace/Message_Queue.h&quot;
+3. #include &quot;ace/Singleton.h&quot;
+
+
+5. typedef ACE_Message_Queue&lt;ACE_MT_SYNCH&gt; Message_Queue;
+6. typedef ACE_Singleton&lt;Message_Queue,ACE_Mutex&gt; Safe_Queue;
+
+ // Declare the thread manager instance - It will track when our
+ // threads exit
+7. static ACE_Thread_Manager thr_mgr;
+
+8. static void *read_queue(void *)
+ {
+
+9. ACE_Thread_Control thread_control (&amp;thr_mgr);
+ // Loop forever , initially declaring an integer variable
+10. for (int result;;)
+ {
+ // Delcare our time out value of 4 seconds
+11. ACE_Time_Value timeout(ACE_OS::time(0)+4,0);
+
+ // Declare the block to hold our message
+12. ACE_Message_Block *data_read;
+13. result = Safe_Queue::instance()-&gt;dequeue_head(data_read,&amp;timeout);
+14. if (result == -1)
+15. break;
+16. cout &lt;&lt; &quot;Received from queue :&quot; &lt;&lt; data_read-&gt;base()&lt;&lt;endl;
+17. delete data_read;
+ }
+18. cout &lt;&lt; &quot;The reader thread has timed out&quot; &lt;&lt; endl;
+ }
+
+19. static void *write_queue(void *)
+ {
+20. ACE_Thread_Control thread_control (&amp;thr_mgr);
+21. char data_write[30];
+
+22. for (int i=0;i&lt;5;i++)
+ {
+
+ // Place our message into our message array
+23. sprintf(data_write,&quot;This is message number %d&quot;,i);
+
+24. ACE_Message_Block *data_send = new
+25. ACE_Message_Block(sizeof(data_write),ACE_Message_Block::MB_DATA,0,data_write);
+
+26. if (Safe_Queue::instance()-&gt;enqueue_tail(data_send) == -1)
+27. ACE_ERROR((LM_ERROR, &quot;(%t) %p\n&quot;, &quot;put_next&quot;));
+28. cout &lt;&lt; &quot;Wrote to the queue&quot; &lt;&lt; data_send-&gt;base()&lt;&lt;endl;
+29. sleep(2);
+ }
+30. cout &lt;&lt; &quot;Writer thread has finished&quot; &lt;&lt; endl;
+ }
+
+31. int main (int argc,char *argv[])
+ {
+32. if (thr_mgr.spawn(ACE_THR_FUNC(write_queue),NULL,THR_NEW_LWP|THR_DETACHED) == -1)
+33. ACE_ERROR_RETURN((LM_ERROR,&quot;%p\n&quot;,&quot;spawing write thread&quot;),1);
+34. if (thr_mgr.spawn(ACE_THR_FUNC (read_queue),NULL,THR_NEW_LWP | THR_DETACHED) == -1)
+35. ACE_ERROR_RETURN((LM_ERROR,&quot;%p\n&quot;,&quot;spawing read thread&quot;),1);
+
+ // Wait for the two threads to exit
+36. thr_mgr.wait();
+
+37. return 0;
+ }
+</PRE>
+</UL>
+
+<P>
+<HR></P>
+
+<P>The program given above is a simple example of a message queue implementation
+which has two threads which read and write from an <I>ACE_Message_Queue</I>.
+As both threads are reading and writing from the same queue, the possibility
+exists for a resource conflict, so we use the idea of &quot;Double Checked
+locking&quot;. This is a mechanism which is based on the Singleton idea
+whereby a class has one and only one instantiation and only has one point
+of entry, and is wrapped up in the <I>ACE_Singleton </I>wrapper class .
+This prevents multiple threads initialising the message queue object concurrently,
+which avoids the potential problems associated with this. When either of
+our objects need a reference to the message queue. they call the <TT>instance</TT>
+function which returns a reference to the queue. </P>
+
+<P>Thread Managers : As stated in the manual &quot;<I>allows operations
+on groups of threads atomically</I>&quot;. The <I>ACE_Thread_Manager </I>is
+basically a class that is used to manage multiple threads , allowing a
+program to easily manipulate groups of threads , such as shutting down
+all of the threads registered with the manager. We also introduce the <I>ACE_Thread_Control
+</I>, which is described in the manual as a mechanism &quot;<I>used to
+keep track of a threads activity within its entry point function</I>&quot;.
+The thread control class is important for tasks such as properly exiting
+a thread manager, and can be used for tasks such as setting the threads
+exit status. We use the control in our message queue example so that once
+the thread exits, the thread control destructor automatically takes care
+of deregistering the thread from the thread manager.</P>
+
+<P>As promised, I will now break up the program into sections which I will
+explain ....</P>
+
+<P>Code outside of main :</P>
+
+<UL>
+<P>We start by declaring our header files. As we use threads, message queues,
+and singletons, we include all three of the header files for these concepts.
+We then define a type based on the <I>ACE_Message_Queue</I> template ,
+specifying ACE_MT_SYNCH, which templates the code so that it is thread
+safe. Note that if the queue does not need to be thread safe , the flag
+ACE_NULL_SYNCH can be passed into the template definition. By passing the
+ACE_MT_SYNCH flag into the template, we are creating additional overhead,
+but resource issues are dealt with automatically by the message queue code.
+Another important issue of concurrency is that of the creation of the message
+queue reference. We are implementing multiple threads, so the possibility
+exists that our two threads could try and initialise a message queue object
+concurrently - This is bad - very bad!!!! We therefore use the <I>ACE_Singleton</I>
+wrapper class that provides our one point of entry to the reference (ie
+the <TT>instance</TT>()) function call). This ensures that the message
+queue is created once and only once. The <I>ACE_Singleton </I>wrapper class
+takes two parameters - a type and a locking mechanism. In this instance
+, we need mutual exclusion on the creation of the queue, so we pass it
+an <I>ACE_Mutex</I> type. This demonstrates the flexibility of using templates,
+whereby the ACE_Singleton class can be used by any type of class to ensure
+one point of entry and only one instantiation of itself. We also declare
+our <I>ACE_Thread_Manager</I> outside of main to manage the threads , thereby
+giving global acces to it from out two threads.</P>
+</UL>
+
+<P><TT>main :</TT></P>
+
+<UL>
+<P>Main is our driver program which starts the program running. We use
+the <I>ACE_Thread_Manager </I>global reference to spawn off our reader
+and writer threads and then simply wait for the threads to exit. We use
+the <TT>wait </TT>function call of the thread manager to block until no
+more threads are registered in the thread manager. As stated above , our
+thread control object deregisters the thread from its manager automatically
+when the thread exits. Note that we could also use a timeout value in the
+<TT>wait</TT> call to allow the manager to time-out after a specified time.</P>
+</UL>
+
+<P><TT>read_queue :</TT></P>
+
+<UL>
+<P>The thread which reads off our global message queue. We first declare
+our thread control, which takes care of cleaning up the thread on exit.
+Note we pass it the address of the thread manager this thread is registered
+with - this will be used by the thread control to deregister the thread
+properly and inform the proper thread manager on exit. We then proceed
+to enter an infinite loop , reading off our global message queue. Note
+the use of the <TT>dequeue_head</TT> function call of the message queue
+class - This will block until a message block can be read off the queue
+or a timeout specified expires, upon which the call returns -1. We use
+this timeout mechanism to terminate the reader thread , by passing a timeout
+value of 4 seconds into the <TT>dequeue_head </TT>call, and if a -1 is
+returned we exit the thread. We read our queue into an object of type <I>ACE_Message_Block</I>
+- this is because only objects of type <I>ACE_Message_Block</I> can be
+placed in an <I>ACE_Message_Queue</I>. However, as will be seen in our
+<TT>write_queue</TT> description, we can pass different types of data within
+the <I>ACE_Message_Block</I>.</P>
+</UL>
+
+<P><TT>write_queue :</TT></P>
+
+<UL>
+<P>The thread that writes to the global message queue. Again we declare
+our thread control to clean up properly , which deregisters us from the
+thread manager. We use the sprintf function to copy our message into our
+buffer to send onto the queue, and declare a new message block based on
+this data. Objects of type <I>ACE_Message_Block</I> are the only types
+that can be placed/manipulated in an <I>ACE_Message_Queue</I>. Note however
+that we can pass the data type into the contructor of the <I>ACE_Message_Block,
+</I>thus allowing us the freedom of declaring different message types (eg.
+signals). This is achevieved by using the predefined types in the <I>ACE_Message_Type
+</I>wrapper class. After declaring our message block , it is a matter of
+just putting the message block in the queue by using the <TT>enqueue</TT>
+function call. A -1 will be returned if an error occurs while placing the
+message block on the queue. This whole process will be repeated 5 times
+by using our while loop, upon which time it will exit, and the thread control
+will clean up. Note the use of the sleep(2) call in our writer - this is
+simply to slow down the writer thread so that our screen output will be
+easier to read (our &quot;cout's&quot;..etc...).</P>
+<TT></TT></UL>
+
+<P>Summary :&nbsp; In this tutorial, we examined the <I>ACE_Message_Queue</I>
+class, which provides a number of functions that allow objects of type
+<I>ACE_Message_Block</I> to be inserted and deleted from a message queue
+object. Apparently , you can enqueue at either the head or the tail of
+the queue, but you can only remove objects from the head of the queue.
+In this tutorial we also introduced the notion of the<I> ACE_Thread_Manager</I>
+and <I>ACE_Thread_Control</I> which provide an interface for managing threads
+efficiently, and introduced the <I>ACE_Singleton </I>class to incorporate
+concurrency protection when using a multithreaded program. All of these
+features will be used extensively in future tutorials as we build toward
+our Thread Pool server , and it is important to have at least a basic understanding
+of their operation.</P>
+
+<P>
+<HR WIDTH="100%"></P>
+
+<CENTER><P>[<A HREF="../../Tutorial">Tutorial Index</A>] [<A HREF="page01.html">Previous
+Page</A>] [<A HREF="page03.html">Continue This Tutorial</A>] </P></CENTER>
+
+</BODY>
+</HTML>
diff --git a/docs/tutorials/006/page02.html b/docs/tutorials/006/page02.html
new file mode 100644
index 00000000000..f36d20cc4e6
--- /dev/null
+++ b/docs/tutorials/006/page02.html
@@ -0,0 +1,6 @@
+<BODY text = "#000000" link="#000fff" vlink="#ff0f0f" bgcolor="#ffffff">
+
+
+See the file <A HREF="notify.cpp">notify.cpp</A>
+for what we're trying to accomplish.
+
diff --git a/docs/tutorials/006/server b/docs/tutorials/006/server
new file mode 100644
index 00000000000..01e32302b13
--- /dev/null
+++ b/docs/tutorials/006/server
Binary files differ
diff --git a/docs/tutorials/006/server.cpp b/docs/tutorials/006/server.cpp
new file mode 100644
index 00000000000..c6a18fad1e1
--- /dev/null
+++ b/docs/tutorials/006/server.cpp
@@ -0,0 +1,388 @@
+// $Id$
+
+#include "ace/Acceptor.h"
+#include "ace/SOCK_Acceptor.h"
+#include "ace/Reactor.h"
+#include "ace/Thread.h"
+#include "ace/Singleton.h"
+#include "ace/Message_Queue.h"
+
+static sig_atomic_t finished = 0;
+static ACE_Thread_Manager thr_mgr;
+static const u_short PORT = ACE_DEFAULT_SERVER_PORT;
+
+extern "C" void handler (int) { finished = 1; }
+
+typedef ACE_Message_Queue<ACE_MT_SYNCH> Message_Queue;
+typedef ACE_Singleton<Message_Queue,ACE_Mutex> Safe_Queue;
+typedef ACE_Singleton<ACE_Reactor,ACE_Mutex>g_reactor;
+
+
+#define MAX_HANDLERS 10
+
+class Logging_Handler;
+
+// Used to hold our array of service handler pointers so we can pass the proper
+// service handler object to our notify call when we want to alert a reactor
+
+Logging_Handler *map[MAX_HANDLERS];
+
+// Used to hold the next non-used position in our service handler array
+int nextFree = -1;
+
+// Used to denote which service handler thread we are referring to
+int whichOne = 0;
+
+// Creates a critical section in the svc() function of the active objects
+// so that only one at a time can add itself to the map.
+ACE_Mutex addlock_;
+
+class Queue_Derived : public ACE_Message_Queue<ACE_MT_SYNCH>
+{
+ public :
+ Queue_Derived() : ()
+ {
+ reactor_ = NULL;
+ }
+
+ // Sets the reactor for this queue - so we can notify the proper reactor
+ // when we need to inform the reactor of an addition to the queue
+ void set_reactor(ACE_Reactor *reactor)
+ {
+ this->reactor_ = reactor;
+ }
+
+ // This is the method called by the queue when item added
+ virtual int notify(void)
+ {
+ // Notify the reactor that a message is on our queue ready to be read. Note the
+ // use of the WRITE_MASK flag which tells our reactor to call the handle_output
+ // function of our intended service handler(which is the first parameter in argument)
+
+ this->reactor_->notify((ACE_Event_Handler *)map[whichOne],ACE_Event_Handler::WRITE_MASK);
+
+ }
+
+ private :
+ ACE_Reactor *reactor_;
+
+};
+
+class Reactor_Derived : public ACE_Reactor
+{
+public:
+ Reactor_Derived() : ()
+ {
+ cout << "*****Calling the reactor constructor*****" << (void *)this << endl;
+ counter = 0;
+ }
+
+ virtual ~Reactor_Derived()
+ {
+ cout << "*****Calling the reactor destructor*****" << (void *)this << endl;
+ }
+
+private:
+ friend class Logging_Handler;
+
+ // counter is used to keep track of the number of service handlers
+ // registered with this reactor (Surely theres a better way ;-)
+ int counter;
+};
+
+class Logging_Handler : public ACE_Svc_Handler<ACE_SOCK_STREAM, ACE_NULL_SYNCH>
+{
+
+public:
+ //Our queue which is going to hold any messages for this logging handler
+ Queue_Derived* local_queue;
+
+ // The reference number of this logging handler object - used when we are deleting
+ // this logging handler object from our global list - so we dont try and write
+ // to a queue that is non-existent
+ int refno = 0;
+
+
+
+ // Return the pointer to the queue associated with this logging handler object
+ Queue_Derived* get_queue(void)
+ {
+ return(this->local_queue);
+ }
+
+ // Basic constructor. This happens when we are built by the acceptor. Since
+ // that will cause us to activate ourselves, we will have to provide the svc()
+ // function and create another of us to handle the actuall connection.
+ //
+
+ Logging_Handler (void)
+ {
+ cerr << "Constructing logging handler " << (void *)this << endl;
+ local_queue = NULL;
+ this->reactor(NULL);
+ }
+
+ // Provide a copy constructor. This will allow us to assume control of
+ // a connection which was being handled by a brother object.
+ //
+ Logging_Handler ( Logging_Handler * foo )
+ {
+ cerr << "Constructing (via pointer) logging handler " << (void *)this << endl;
+ this->set_handle( foo->get_handle() );
+ local_queue = new Queue_Derived;
+ }
+
+ virtual ~Logging_Handler(void)
+ {
+ cerr << "Destructing logging handler " << (void *)this << endl;
+ }
+
+ virtual void destroy(void)
+ {
+ cerr << "Logging handler destroy " << (void *)this << endl;
+
+ // If we're an active object, we don't have (or need) a pointer
+ // to the reactor. We're stuck inside of our svc() function and
+ // never get to do anything else :-(
+ //
+ // On the other hand, if we're actually registered with a reactor
+ // and are doing some work, then we *will* have a pointer to the
+ // reactor we're registred with and we'll need to use it when we
+ // get destroyed.
+ //
+ if(reactor())
+ {
+ // Since we dont want to try and write to a queue that is non-existent,
+ // we have to delete our Logging_Handler reference in our global list
+ // of Logging_Handlers...By setting to null we indicate that the Logging Handler
+ // is no longer existent
+
+ map[this->refno] = NULL;
+
+ // Delete our reference to the queue associated with this Logging Handler
+ delete local_queue;
+
+ // Remove the handler from the local reactors table of registered handlers
+ if (this->reactor()->remove_handler(this,
+ ACE_Event_Handler::READ_MASK | ACE_Event_Handler::DONT_CALL)== -1)
+ ACE_ERROR_RETURN ((LM_ERROR, "can'(%P|%t) t remove service from reactor\n"), -1);
+
+ // Decrement the handler tracking variable in the reactor to
+ // indicate this service handler has terminated
+ --((Reactor_Derived*)reactor())->counter;
+ }
+
+ this->peer ().close ();
+ cout << "About to delete" << (void *)this << endl;
+ delete this;
+ }
+
+ virtual int open(void *)
+ {
+ int foo = 1;
+
+ // Take an arbitrary number 'bar' and activate up to that many
+ // objects to provide reactor loops. On and after the 'bar+1'
+ // connection attempt, register all new connections with the
+ // same reactor that is handling the bar-th connection.
+ // Note that what we have in the map is an array of service
+ // handlers that are registered with reactors. We DO NOT HAVE
+ // an array of pointers to the active objects which provide the
+ // reactor loop. A better approach would be to have an array
+ // of pointers to reactors. We could then keep statistics info
+ // in the reactor object and access that from here to determine
+ // which reactor should have the new connection.
+
+ if( nextFree >= MAX_HANDLERS )
+ {
+ return -1;
+ }
+ else
+ if ((nextFree <foo) || ! map[foo] )
+ {
+ this->activate(THR_NEW_LWP);
+ }
+ else
+ {
+
+ // If we're not going to activate ourselves and we haven't already
+ // done so, now is the time to create a local queue.
+ if( ! local_queue ) local_queue = new Queue_Derived;
+
+ // Likewise, if we don't have a pointer to a reactor, we should get one.
+ if( ! reactor() )reactor( map[foo]->reactor());
+
+ if (map[foo]->reactor()->register_handler(this, ACE_Event_Handler::READ_MASK) == -1)
+ ACE_ERROR_RETURN ((LM_ERROR,"can'(%P|%t) t register with reactor\n"), -1);
+ ++ ((Reactor_Derived*)(map[foo]->reactor()))->counter;
+ }
+ return 0;
+ }
+
+
+ int svc(void)
+ {
+ int result;
+ Reactor_Derived thread_reactor;
+
+ cerr << "Thread reactor is " << (void *)&thread_reactor << endl;
+
+ // Create the object we will actually register with the reactor.
+ // It will be our duty to provide the typical endless-reactor-loop
+ // while we let somebody else have all the fun of handling the connection
+ // we were created to deal with.
+ //
+ Logging_Handler * trueHandler = new Logging_Handler(this);
+
+ // Enter a block of code which adds a reference to this Logging Handler object
+ // into our global table of service handlers
+ {
+
+ // Use the ACE_Gurad class to lock the critical code until the end bracket
+ ACE_Guard <ACE_Mutex> lock (addlock_);
+
+ //Set our reference to this Logging Handler object in the global array
+ map[++nextFree] = trueHandler;
+
+ trueHandler->refno = nextFree;
+ }
+
+ trueHandler->reactor(&thread_reactor);
+ trueHandler->local_queue->set_reactor(trueHandler->reactor());
+
+ this->reactor(0);
+ this->set_handle( ACE_INVALID_HANDLE );
+
+ // Increment our handler counter to account for this trueHandler
+ ++thread_reactor.counter;
+
+
+ if (thread_reactor.register_handler(trueHandler, ACE_Event_Handler::READ_MASK) == -1)
+ ACE_ERROR_RETURN ((LM_ERROR,"can'(%P|%t) t register with reactor\n"), -1);
+
+ while( thread_reactor.counter > 0 )
+ {
+
+ // If thread_reactor.counter = 0 then we have no more service
+ // handlers connected to the reactor. We set a timeout value
+ // of 1 second so that the handle_events loop break out every
+ // second to check on the count ( because of it blocking
+ // even when there are no connections we need to do this)
+ thread_reactor.handle_events(ACE_Time_Value(1,0));
+ }
+
+ cerr << "svc exiting scope " << (void *)this <<endl;
+ }
+
+
+ virtual int close (u_long)
+ {
+ this->destroy ();
+ return 0;
+ }
+
+protected:
+
+ virtual int handle_output(ACE_HANDLE)
+ {
+
+ ACE_Time_Value timeout(ACE_OS::time(0)+1,0);
+ ACE_Message_Block *data_read;
+
+ // Read from our queue - waiting for a timeout of 4 seconds(specified in var. timeout)
+ if (this->local_queue->dequeue_head(data_read,&timeout) != -1)
+ {
+ cout << " Received some data! : " << (void *)data_read->base() << " " << data_read->base() << endl;
+ cout << " This data was recevied from queue number : " << this->refno << endl;
+ //delete data_read;
+ }
+ else
+ cout << "No data to dequeue " <<endl;
+
+
+
+ return 0;
+ }
+
+ virtual int handle_input (ACE_HANDLE)
+ {
+ char buf[128];
+ memset(buf,0,sizeof(buf));
+
+ switch( this->peer().recv(buf,sizeof buf) )
+ {
+ case -1:
+ ACE_ERROR_RETURN ((LM_ERROR, "(%P|%t) %p bad read\n", "client logger"), -1);
+ case 0:
+ ACE_ERROR_RETURN ((LM_ERROR, "(%P|%t) closing log daemon (fd = %d)\n", this->get_handle ()), -1);
+ default:
+ cout << "Received from client : " << buf;
+ }
+
+
+ return 0;
+ }
+
+};
+
+
+typedef ACE_Acceptor <Logging_Handler, ACE_SOCK_ACCEPTOR> Logging_Acceptor;
+
+
+int main (int argc, char *argv[])
+{
+ char data_write[60] = "This is a message from the main thread.....!!";
+
+ // Acceptor factory.
+ Logging_Acceptor peer_acceptor;
+
+ if (peer_acceptor.open (ACE_INET_Addr ( argc > 1 ? atoi(argv[1]) : PORT)) == -1)
+ ACE_ERROR_RETURN ((LM_ERROR, "%p\n", "open"), -1);
+
+ else if (g_reactor::instance()->register_handler (&peer_acceptor, ACE_Event_Handler::READ_MASK) == -1)
+ ACE_ERROR_RETURN ((LM_ERROR, "registering service with ACE_Reactor\n"), -1);
+
+ ACE_Sig_Action sa ((ACE_SignalHandler) handler, SIGINT);
+
+ // Run forever, performing logging service.
+
+ ACE_DEBUG ((LM_DEBUG, "(%P|%t) starting up server logging daemon\n"));
+
+ // Perform logging service until QUIT_HANDLER receives SIGINT.
+
+ while ( !finished )
+ {
+ ACE_Message_Block *data_send = new ACE_Message_Block(sizeof(data_write),ACE_Message_Block::MB_DATA,0,data_write);
+
+ g_reactor::instance()->handle_events (new ACE_Time_Value(4,0));
+
+
+ // Loop through all of the Logging Handler objects in our global array
+ // The end is indicated by the variable nextFree
+
+ for (int i=0;i<=nextFree;++i)
+ {
+ // If map[i] is equal to NULL then we know that that service handler has
+ // deceased, so we do not want to try and queue a message on its queue
+ if (map[i] != NULL)
+ {
+ // whichOne is a global variable used to determine which service handler
+ // to notify of a queue addition, since each service handler will have
+ // a seperate queue
+ whichOne = i;
+
+ // Place our message on the service handler's queue
+ if (map[i]->local_queue->enqueue_tail(data_send) == -1)
+ cout << "**Error occured while writing to the queue**" << endl;
+ else
+ cout << "\n Wrote to queue number : !!"<<i<<endl;
+ }
+
+ }
+
+
+ }
+ ACE_DEBUG ((LM_DEBUG, "(%P|%t) shutting down server logging daemon\n"));
+
+ return 0;
+}
diff --git a/docs/tutorials/index.html b/docs/tutorials/index.html
new file mode 100644
index 00000000000..25636330fa1
--- /dev/null
+++ b/docs/tutorials/index.html
@@ -0,0 +1,98 @@
+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 3.2//EN">
+<HTML>
+<HEAD>
+ <TITLE>ACE Tutorial Introduction</TITLE>
+ <META NAME="GENERATOR" CONTENT="Mozilla/3.01Gold (Win95; I) [Netscape]">
+ <META NAME="Author" CONTENT="James CE Johnson">
+</HEAD>
+<BODY text = "#000000" link="#000fff" vlink="#ff0f0f" bgcolor="#ffffff">
+
+
+<H1 ALIGN=CENTER>ACE&nbsp;Tutorial<BR>
+A Beginners Guide to Using the ACE&nbsp;Toolkit</H1>
+
+<P>
+<HR WIDTH="100%"></P>
+
+<P>
+A note to those of you reading from the Internet...
+
+<DL>
+<DD>
+The things here are property
+of <A HREF="http://www.lads.com">Automated Design Systems</A>. You are free
+to use this information in any way that will help you learn ACE but please
+do not use it for anything else. Feel free also to link to these pages
+if you think they may be helpful to others. Finally, the material in these
+pages is copyrighted by ADS & not available for publication elsewhere
+without prior approval. (All you have to do is <A HREF="mailto:jcej@lads.com">ask</A>)
+<DD>
+
+</DL>
+
+<HR WIDTH="100%"></P>
+
+<H2>Who should be reading this?</H2>
+
+<P>
+The original audience was the ADS IPC team. Since then, the scope has been
+changed to include anyone wanting to learn about the ACE framework. Hopefully,
+even experienced ACE programmers will find something new here. With a framework
+as encompassing as ACE, it is easy to become an expert in one area and know little
+or nothing about others.
+
+<P>
+<HR WIDTH="100%"></P>
+
+<H2>What is ACE?</H2>
+
+<P>The ACE library was developed mostly by
+<A HREF="http://www.cs.wustl.edu/~schmidt">Douglas C. Schmidt's</A>
+team at Washington
+University. The library attempts to abstract the details of many things
+across many operating systems. Some of the things abstracted include: network
+programming, multi-threading, shared memory and resource locking. The library
+has been ported to many Unix variants as well as Win32 (NT/95).</P>
+
+<P>The reason to use ACE is simple: write a multi-threaded networked application
+on one platform and quickly be able to use it on another. This is important
+in the scope of the AMS project because it will be necessary for the many
+AMS applications to communicate with one another. The applications will
+exist on Unix and Win32 platforms within a local area network.</P>
+
+<HR WIDTH="100%"></P>
+
+<H2>What about TAO?</H2>
+
+<P>In the early stages, these tutorials won't address The ACE Orb
+(<A HREF="http://www.cs.wustl.edu/~schmidt">TAO</A>).
+However... if you want to request a tutorial on some aspect of TAO or even create
+one yourself, I'll be glad to integrate those into these tutorials. It's rare
+when folks want to write documentation, nothing will be refused :-></P>
+
+<HR WIDTH="100%"></P>
+
+<H2>The Tutorials</H2>
+
+<OL>
+<LI><A HREF="001/page01.html">A Simple Server</A></LI>
+
+<LI><A HREF="002/page01.html">A Simpler Server</A></LI>
+
+<LI><A HREF="003/page01.html">Finally, a Client</A></LI>
+<LI><A HREF="004/page01.html">A much <I>cooler</I> client</A></LI>
+
+<LI><A HREF="005/page01.html">A server that handles it's connections in dedicated threads</A></LI>
+<LI><A HREF="006/index.html">Like #5 but each thread can handle multiple connections</A></LI>
+
+<LI><A HREF="007/">A client that forces all connection activities into a dedicated thread</A></LI>
+<LI><A HREF="008/">A melding of #6 and #7</A></LI>
+
+<LI>Next Tutorial</LI>
+</OL>
+
+<P>
+<HR WIDTH="100%"></P>
+
+</BODY>
+</HTML>
diff --git a/docs/tutorials/linify b/docs/tutorials/linify
new file mode 100755
index 00000000000..f44747f5269
--- /dev/null
+++ b/docs/tutorials/linify
@@ -0,0 +1,52 @@
+#!/usr/local/bin/perl
+
+while( $#ARGV > -1 ) {
+
+ print "$ARGV[0]\n";
+
+ $source = "$ARGV[0]";
+
+ if( $source =~ /~$/ ) {
+ $dest = "$`";
+ } else {
+ rename("$source","$source"."~") || die "Cannot rename ($source)";
+ $dest = "$source";
+ $source .= "~";
+ }
+
+ open(INPUT,"<$source") || die "Cannot open ($source)";
+ open(OUTPUT,">$dest") || die "Cannot open ($dest)";
+
+ $n = 1;
+
+ $prestrip = 0;
+ while( <INPUT> ) {
+ chomp;
+
+ if( ! $prestrip && /^[0-9]+\.\t/ ) {
+ $prestrip = 1;
+ $_ = $';
+ } elsif( $prestrip ) {
+ if( /^[0-9]+\.\t/ ) {
+ $_ = $';
+ } else {
+ s/^\t//;
+ }
+ }
+
+ if( /^\s*$/ || /^\s*({|})\s*;?\s*$/ || /^\s*\/\//
+ || /^\s*private\s*:/ || /^\s*protected\s*:/ || /^\s*public\s*:/
+ || /^\s*}?\s*else\s*{?\s*:/
+ ) {
+ print OUTPUT "\t$_\n";
+ } else {
+ print OUTPUT "$n.\t$_\n";
+ ++$n;
+ }
+ }
+
+ close(INPUT);
+ close(OUTPUT);
+
+ shift(@ARGV);
+}
diff --git a/docs/tutorials/page03.html b/docs/tutorials/page03.html
new file mode 100644
index 00000000000..836ba7c1ea8
--- /dev/null
+++ b/docs/tutorials/page03.html
@@ -0,0 +1,285 @@
+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 3.2//EN">
+<HTML>
+<HEAD>
+ <TITLE>ACE Tutorial 001</TITLE>
+ <META NAME="GENERATOR" CONTENT="Mozilla/3.01Gold (Win95; I) [Netscape]">
+ <META NAME="Author" CONTENT="James CE Johnson">
+ <META NAME="Description" CONTENT="A first step towards using ACE productively">
+</HEAD>
+<BODY text = "#000000" link="#000fff" vlink="#ff0f0f" bgcolor="#ffffff">
+
+
+<CENTER><P><B><FONT SIZE=+2>ACE&nbsp;Tutorial 001<BR>
+A Beginners Guide to Using the ACE&nbsp;Toolkit</FONT></B></P></CENTER>
+
+<P>
+<HR WIDTH="100%"></P>
+
+<P>Now we begin to look at the acceptor object.</P>
+
+<P>I will present the entire object header file first and then disect it
+as with <I>main()</I>.</P>
+
+<UL>
+<PRE>1. #include &lt;stdio.h&gt;
+
+2. #include &quot;ace/Reactor.h&quot;
+3. #include &quot;ace/Event_Handler.h&quot;
+4. #include &quot;ace/SOCK_Acceptor.h&quot;
+5. #include &quot;ace/SOCK_Stream.h&quot;
+6. #include &quot;ace/INET_Addr.h&quot;
+
+7. #include &quot;logger.h&quot;
+
+
+8. extern ACE_Reactor g_reactor;
+
+9. class Client_Acceptor : public ACE_Event_Handler
+ {
+
+10. public :
+
+11. Client_Acceptor( const ACE_INET_Addr &amp;addr) : acceptor_(addr) {
+12. if( ! (fp = fopen(&quot;acceptor&quot;,&quot;w+&quot;)) )
+13. fp = stderr;
+
+14. fprintf(fp,&quot;Constructed\n&quot;);
+ }
+
+15. virtual int handle_exception(ACE_HANDLE handle)
+ {
+16. fprintf(fp,&quot;Exception\n&quot;);
+17. return(-1);
+ }
+
+18. virtual int handle_input(ACE_HANDLE handle)
+ {
+19. ACE_SOCK_Stream new_connection;
+
+20. this-&gt;acceptor_.accept(new_connection);
+
+21. Logging_Handler *cli_handler = new Logging_Handler(new_connection);
+
+22. fprintf(fp,&quot;Got New Connection\n&quot;);
+
+23. int foo = g_reactor.register_handler(cli_handler,ACE_Event_Handler::RWE_MASK);
+24. return( foo );
+ }
+
+25. virtual ACE_HANDLE get_handle(void) const
+ {
+26. fprintf(fp,&quot;Providing Handle\n&quot;);
+27. return this-&gt;acceptor_.get_handle();
+ }
+
+28. virtual void handle_close(void)
+ {
+29. this-&gt;acceptor_.close();
+30. fprintf(fp,&quot;Closing\n&quot;);
+ }
+
+31. private :
+32. ACE_SOCK_Acceptor acceptor_;
+33. FILE * fp;
+34. };
+
+</PRE>
+</UL>
+
+<P>Here's a blow-by-blow account of what's being done:</P>
+
+<OL START=1>
+<LI>Include the standard I/O&nbsp;system header file. I only need this
+so that I&nbsp;can use <I>fprintf</I> stuff for the logging function. In
+reality we would probably talk to a database or something.</LI>
+
+<LI>Bring in the ACE headers. Don't worry about the details here.</LI>
+</OL>
+
+<OL START=7>
+<LI>Bring in the definition of the <I>logger</I> object. The logger will
+handle connections after our acceptor has accepted the connection. We'll
+look at that on the next page.</LI>
+
+<LI>Provide quick access to the reactor object. Later tutorials will be
+more clever than this...</LI>
+
+<LI>Derive our new acceptor object from the ACE_Event_Handler base-class.
+The event handler object is designed to work with the reactor. When an
+event handler is registered with a reactor, the reactor uses member functions
+of the event handler object to gain access to the underlying connection
+<I>handle.</I> We saw this registration process in the previous example
+when the acceptor object was registered with the reactor in the <I>main()</I>
+function. On Unix-type systems, the reactor will then use the <I>select</I>
+system call to wait for activity on the handle (on Win32, <I>WaitForMultipleObjects</I>
+is used instead). Once activity is detected on the handle by the reactor,
+different member functions of the event handler are invoked to process
+the activity. We'll see these in the lines below.</LI>
+
+<LI>Most of the object is going to be public. When we get a little better
+at what we're doing, we can try to make it safer by declaring some of these
+protected. Most of them can never be private however. Notice at this point
+how each of the functions is declared to be a virtual. This MUST be done
+so that if we later derive a class from here the runtime environment will
+get the member function of the derived class instead of that of the baseclass.</LI>
+
+<LI>The object constructor is the only non-virtual function. We may find
+out later that it should have been virtual! Anyway, we take the single
+parameter, a reference to an address object, and use it to initialize our
+<I>acceptor_</I> object. This is the object which will actually listen
+for client connections. There is a discussion below about why the Acceptor
+is a member of our object rather than it's base class.</LI>
+
+<LI>Remove the gag from the object by giving it somewhere to write debug
+information to. We'll use this file pointer throughout the object to keep
+track of it's internal activities.</LI>
+
+<LI>Fall back to <I>stderr</I> if we failed to open our output file.</LI>
+
+<LI>Status message (duh).</LI>
+
+<LI>The <I>handle_exception</I> member function will be called by the reactor
+if an exception is noticed on the handle associated with this object. In
+the case of a connected socket, an exception is generally caused when the
+remote side closes the connection. In the case of a listening socket, it
+could indicate som rare and strange network failure. See the <I>man</I>
+pages for <I>accept</I> and <I>listen</I> if you really care. For our purposes,
+if we get an exception on our acceptor then we return <I>-1</I> to the
+reactor which tells it we're out of commission. At that point the reactor
+will invoke our <I>close</I> funtion and shut us down.</LI>
+
+<LI>Display notification of the error.</LI>
+
+<LI>Return -1 to tell the reactor that we should be shut down.</LI>
+
+<LI>The <I>handle_input</I> method is called by the reactor whenever our
+handle has some data available for us to process. The actual handle is
+passed into the function but we won't be using it because we know it MUST
+be the <I>acceptor_</I> member object. We could compare the two as a safety
+check though.</LI>
+
+<LI>Now we are creating a new connection. It will be this connection which
+we use to communicate with the client. This will free up the acceptor to
+listen for more connection requests. Because the acceptor as a <I>SOCK
+</I>type object we need to create the connection as a <I>SOCK</I> also.
+An <I>ACE_SOCK_Stream</I> will provide us with an end-to-end connection
+similar to a pipe. This gives us the guarantee that any data we send or
+receive will be complete and in the correct order. An <I>ACE_SOCK_Dgram</I>
+could be used if we don't mind missing some packets or receiving them out
+of order.</LI>
+
+<LI>The <I>acceptor_</I> member object is now told to accept the client
+connection and attach it to the new <I>ACE_SOCK_Stream</I> object we just
+created. This is what frees up the acceptor to listen for more new connections.
+If you don't <I>accept</I> the connection, you cannot read the client's
+data and new clients cannot connect. In fact, after a timeout, the client
+which caused this <I>handle_input</I> callback will give up and assume
+the connection failed.</LI>
+
+<LI>Up to this point, we haven't done anything very specific with regards
+to our application. Here, however, we finally create a <I>logger</I> object
+to handle the connection. The logger object is something we defined in
+<I>logger.h</I>. It is given an <I>ACE_SOCK_Stream</I> object on which
+it will communicate. This is the <B>only</B> application-specific code
+you will find in the <I>Client_Acceptor</I> object we are developing here.</LI>
+
+<LI>Announce the new connection. We could use member functions of <I>new_connection</I>
+to report either of the local and remote systems' addresses and names.</LI>
+
+<LI>Finally, we register our <I>Logging_Handler</I> with our reactor. This
+tells the reactor about our new connection and tells it who to inform when
+there is activity on the connection. Note that we use the <I>RWE</I> mask
+so that we get notification when the connection has data for us to read,
+is available for us to write upon* and when it takes an error. (* Because
+of network buffers and such, you can't necessarily write on a connection
+anytime you want. At times, a <I>write</I> operation on a connection will
+fail or partially fail due to full buffers or some other network issue.
+When that happens, you must cache the remaining data to be written and
+wait for the write-notification event.)</LI>
+
+<LI>Return the result of registering the new connection. If the registration
+failed for some reason, this will cause the <I>handle_input</I> to fail
+and, ultimately, shut down the server. There is probably a much better
+way to handle this but it serves our purposes at the moment.</LI>
+
+<LI><I>get_handle</I> provides an interface layer between the reactor with
+which we're registered and the connection we wish the reactor to operate
+on. The reactor does it's job by monitoring one or more <I>handles</I>.
+In the Unix world, these are simply file descriptors. The <I>get_handle</I>
+method of a communcations object such as our <I>acceptor_</I> returns the
+underlying socket file descriptor associated with the connection. Because
+other OSes work differently, however, the <I>get_handle</I> method provides
+insulation for the programmer. By doing this, the programmer has the option
+of registering many types of objects with a reactor: disk-based file, serial
+port, intra-process pipes, etc...</LI>
+
+<LI>Progress notification.</LI>
+
+<LI>Return the handle of the actual communcation's object.</LI>
+
+<LI>Similar to <I>get_handle</I>, the <I>handle_close</I> is a wrapper
+that allows the reactor to close a connection object. Again, this does
+not have to be an IPC object, it could be anything that supports basic
+open/read/write/close functionality. What we're doing here is shutting
+down the acceptor. You would do this when you want to bring down or pause
+the server.</LI>
+
+<LI>Perform the actual close operation.</LI>
+
+<LI>Another notification</LI>
+
+<LI>Now we begin our brief section of private data. In a real application
+this might be <I>protected</I> instead so that a derived object would have
+direct access to the data members. On the other hand, we may not want that...</LI>
+
+<LI>The <I>acceptor_</I> member object is where all of the action centers.
+It is this object which abstracts all of the socket-level mess necessary
+to listen for client connection requests.</LI>
+
+<LI>The file pointer is our simple way of reporting progress throught the
+program and logging activity from the client.</LI>
+
+<LI>All Done.</LI>
+</OL>
+
+<P>It is important to notice here that we have done very little application-specifc
+code in developing this object. In fact, if we take out the progress information,
+the only app-specific code is when we create the new <I>Logging_Handler</I>
+object to give to the <I>accept</I> function. You may begin to wonder why
+there isn't a C++&nbsp;template that does all of this coding for you. Actually,
+the ACE toolkit happens to have one handy:</P>
+
+<UL>
+<P>typedef ACE_Acceptor &lt;<I>YourHandlerClass</I>, ACE_SOCK_ACCEPTOR&gt;
+<I>YourAcceptorClass</I>;</P>
+</UL>
+
+<P>We would have used it like this:</P>
+
+<UL>
+<P>typedef ACE_Acceptor &lt;Logging_Handler, ACE_SOCK_ACCEPTOR&gt; Client_Acceptor;</P>
+</UL>
+
+<P>This will create a piece of code similar to what I've shown above. The
+primary difference is that the <I>handle_input </I>function created by
+the template does NOT register the handler with the reactor. In the long-run,
+that is good for us because we can then move that logic into the <I>open</I>
+function of the <I>Logging_Handler</I> and use a completely-generic acceptor.</P>
+
+<P>Now that we know how to accept a connection request, let's move on to
+the next page where we learn how to handle the actual connection. Even
+though we just learned about this cool template thing, we will continue
+to use the &quot;hand-written&quot; acceptor developed above. As I mentioned,
+the only difference will be in the <I>open</I> function of the connection
+handler anyway.</P>
+
+<P>
+<HR WIDTH="100%"></P>
+
+<CENTER><P>[<A HREF="..">Tutorial
+Index</A>] [<A HREF="page02.html">Previous
+Page</A>] [<A HREF="page04.html">Continue
+This Tutorial</A>] </P></CENTER>
+
+</BODY>
+</HTML>
diff --git a/etc/ACE-tutorials-intro.html b/etc/ACE-tutorials-intro.html
new file mode 100644
index 00000000000..f8685bea71a
--- /dev/null
+++ b/etc/ACE-tutorials-intro.html
@@ -0,0 +1,72 @@
+<TITLE>ACE Beginners' Guide</TITLE>
+<BODY text = "#000000" link="#000fff" vlink="#ff0f0f" bgcolor="#ffffff">
+
+<CENTER><H1>The Beginners' Guide to ACE</H1></CENTER>
+<P>
+
+This site is dedicated to developing a set of tutorials to get ACE
+newcomers up to speed with the framework. For now, this will be
+limited strictly to ACE matters but I'm not opposed to setting up a
+separate area for TAO. In fact, I encourage it! <P>
+
+Here are some general guidelines for creating tutorials:
+<P>
+<UL>
+<LI> Choose a topic that you know very well or are just learning.
+<P>
+ This isn't really a conflict...
+<P>
+ If you know a topic very well, you're likely to know what is most
+ important to the novice and what can be left until later. If you're
+ just learning a topic, then you know what questions you have that
+ must be answered before you can continue.
+<P>
+<LI> Keep it simple.
+<P>
+ Don't try to use a lot of really cool ACE features along the way. Stick
+ to the basic stuff and show that. Try to use a minimum of ACE objects
+ that are not the direct target of the tutorial.
+<P>
+ (For instance, don't get all caught up in ACE_Singleton<> if you're
+ trying to show how to use an ACE_Reactor.)
+<P>
+ If you want to show something really cool that happens to depend on
+ another ACE feature, do a tutorial on that other feature first! I've
+ found that folks will tend to get stuck on *anything* they don't
+ understand even if it isn't directly relevant to what you're trying
+ to teach.
+<P>
+<LI> Document the heck out of it!
+<P>
+ There's no such thing as too much documentation. Don't worry about
+ repeating yourself along the way. Assume that the reader knows nothing
+ at all about the topic at hand and explain even the parts that you feel
+ are painfully obvious.
+<P>
+ If you feel that sticking a bunch of comments in the code makes it harder
+ to read then stick in a label and document at the end of the file or
+ something. Alternately, create both a well-documented version and a
+ sparsely-documented version. Then folks can choose between 'em.
+<P>
+<LI> Over-teach it.
+<P>
+ If there's a tutorial created for a topic that you feel strong in,
+ create another one anyway. Everybody tends to code a little differently.
+ Perhaps your tutorial style will "feel" better to some newcomers
+ than an existing tutorial. You won't hurt anybody's feelings if
+ you present the same material in a different way.
+<P>
+<LI> Steal existing code.
+<P>
+ The ultimate form of code reuse :-) Seriously... grab one or more
+ of the existing ACE tests or examples. Then strip it down to the
+ bare bones & add heaps of comments. I don't think the software-police
+ will be coming after anyone for that!
+</UL>
+<P>
+If this thing takes off, I'll start to organize the tutorials into
+groups. For now, lets concentrate on quantity & quality. Organization
+can come later...
+<P>
+<A HREF="tutorials">Follow this link to the tutorials...</A>
+
diff --git a/etc/ACE-tutorials-overview.html b/etc/ACE-tutorials-overview.html
new file mode 100644
index 00000000000..44d21201795
--- /dev/null
+++ b/etc/ACE-tutorials-overview.html
@@ -0,0 +1,50 @@
+<BODY text = "#000000" link="#000fff" vlink="#ff0f0f" bgcolor="#ffffff">
+
+<B>What's here?</B>
+<P>
+
+<LI><A HREF="Examples">Examples</A>
+<UL>
+ Very rough proof of concept apps used during my
+ ACE learning phase. The stuff here was used as
+ the stepping stone to create the initial Tutorials
+</UL>
+
+<LI><A HREF="tutorials">Tutorials</A>
+<UL>
+ A refinement of the Examples. There are only a
+ handfull of tutorials here but they should give
+ you an idea of the direction I was taking.
+</UL>
+
+<LI><A HREF="Guidelines.html">Guidelines.html</A>
+<UL>
+ A rough-draft of guidelines for creating a new set
+ of Tutorials more up to date and generally useful.
+</UL>
+
+<LI><A HREF="Mail">Mail</A>
+<UL>
+ This was to be a collection of mail messages relevant
+ to our development process. Since then, I've started
+ filing everything in my personal mailbox...
+ If this site begins to get a lot of traffic, I'll move
+ this somewhere less intrusive. (Likewise for the
+ <i>acemail</i> file.)
+</UL>
+</UL>
+<P>
+Except for the Guidelines, all of what you see is very out
+of date. Probably on the order of a year or so. Still,
+the direction and goal remain the same: create a set of
+tutorials that can be used by experienced C++/OOP programmers
+to learn the ACE framework.
+<P>
+I encourage any readers of this page to contact me if you have
+suggestions or want to create a tutorial of your own.
+During "normal business hours" (EST) you can get me quickest
+at <A href="mailto:jcej@lads.com">jcej@lads.com</A>.
+After dark & on the weekends you'll find
+me at home: <A HREF="jcej@tragus.org">jcej@tragus.org</A>.
+Of course, I'm always checking the ACE mailing list.
+<P>