summaryrefslogtreecommitdiff
path: root/comm/OLD/TextServer.cc
diff options
context:
space:
mode:
Diffstat (limited to 'comm/OLD/TextServer.cc')
-rw-r--r--comm/OLD/TextServer.cc337
1 files changed, 337 insertions, 0 deletions
diff --git a/comm/OLD/TextServer.cc b/comm/OLD/TextServer.cc
new file mode 100644
index 0000000..4b9ac14
--- /dev/null
+++ b/comm/OLD/TextServer.cc
@@ -0,0 +1,337 @@
+/*
+ * The Unix Channel
+ *
+ * by Michel Beaudouin-Lafon
+ *
+ * Copyright 1990-1993
+ * Laboratoire de Recherche en Informatique (LRI)
+ *
+ * Text-oriented servers
+ *
+ * $Id$
+ * $CurLog$
+ */
+
+#include "TextServer.h"
+#include "Multiplexer.h"
+#include "TimeOut.h"
+#include "error.h"
+#include "PortServer.h"
+#include <stdio.h>
+
+/* every REG_TIME milliseconds, the server registers to the port server
+ we want this time to be shorter than the REG_TIME of the port server.
+ half the value of the port server's REG_TIME seems reasonable */
+#define REG_TIME 30000
+
+class UchTextServerTimer : public UchBaseTimeOut {
+protected:
+ UchTextServer* Server;
+
+public:
+ UchTextServerTimer (UchTextServer*);
+ ~UchTextServerTimer ();
+ void Handle (Millisecond);
+};
+
+UchTextServerTimer :: UchTextServerTimer (UchTextServer* s)
+: UchBaseTimeOut (*s->GetMultiplexer (), REG_TIME),
+ Server (s)
+{
+ Handle (0);
+}
+
+
+UchTextServerTimer :: ~UchTextServerTimer ()
+{
+ PortServerRemove ("agent", Server->service, Server->BoundTo ());
+}
+
+void
+UchTextServerTimer :: Handle (Millisecond)
+{
+ PortServerRegister ("agent", Server->service, Server->BoundTo ());
+}
+
+
+/*?
+Create a \var{UchTextServer} registered with the portserver under the name \var{serv}.
+\var{newcl} is the function that instantiates clients.
+It takes a pointer to this server as argument, and must return a dynamically
+allocated object of a derived class of \var{UchTextClient}.
+In most cases, the function's body is \com{return new MY_CLIENT (s);},
+if \typ{MY_CLIENT} is the derived class of \var{UchTextClient} defined
+by the application and \var{s} is this server.
+?*/
+UchTextServer :: UchTextServer (const char* serv, fNEW_CLIENT newcl)
+: UchStream (new UchInetAddress (ANYADDR), 0),
+ Timer (0),
+ ok (FALSE),
+ Clients ()
+{
+ service = serv;
+ newClient = newcl;
+}
+
+/*?
+Remove the service name from the port server.
+This destructor does not close down the server.
+Use \fun{Quit} to terminate the server properly.
+?*/
+UchTextServer :: ~UchTextServer ()
+{
+ if (Timer)
+ delete Timer;
+}
+
+/*?
+Initialize the server, register it with the multiplexer,
+and register its address with the port server.
+?*/
+bool
+UchTextServer :: Init (UchBaseMultiplexer& mpx)
+{
+ if (Listen () < 0) { // calls Setup
+ SysError (ErrWarn, "UchTextServer::Setup");
+ return FALSE;
+ }
+ mpx.Add (*this);
+ ok = TRUE;
+ char buf [128];
+ sprintf (buf, "listening on port #%d", (void*) ((UchInetAddress*) BoundTo ())->Port ());
+ Error (ErrLog, "UchTextServer::Init", buf);
+ Timer = new UchTextServerTimer (this);
+ return TRUE;
+}
+
+/*?
+Terminate the server.
+First each client is notified that the server is about to quit by calling
+its \var{Quitting} virtual member and removing it from the multiplexer.
+This should normally delete the client.
+Finally, the server itself is removed from the multiplexer, which should
+delete it in a similar way.
+?*/
+void
+UchTextServer :: Quit ()
+{
+ if (! ok)
+ return;
+ ok = FALSE;
+ // a bit tricky because of the smart pointers:
+ // each tstream probably is referenced only through the multiplexer
+ // removing it from the multiplexer hence deletes it.
+ // The same thing holds for the UchTextServer itself
+ // this is why we delete it last.
+ // Finally, this should make the multiplexer loop exit,
+ // if there are no other channels in the multiplexer.
+#ifndef CPLUS_BUG19
+ CcuListIterOf <UchTextClient> ci = Clients;
+ while (++ci) {
+ UchTextClient* c = *ci;
+#else
+ CcuListIter ci = Clients;
+ while (++ci) {
+ UchTextClient* c = (UchTextClient*) *ci;
+#endif
+ c->Quitting ();// signal the client we're leaving
+ if (Mpx)
+ Mpx->Remove (*c);
+ }
+ Mpx->Remove (*this);
+}
+
+/*?
+Remove a client from the client list and unregister it from the multiplexer.
+This should delete the client, since the multiplexer probably holds the
+last smart pointer to the client.
+This protected function must be called by a client that is about to disappear.
+?*/
+void
+UchTextServer :: Remove (UchTextClient* s)
+{
+ if (! ok)
+ return;
+
+ int found = Clients.Remove (s);
+
+ if (!found)
+ Error (ErrWarn, "UchTextServer::Remove", "stream not in client list");
+
+ if (Mpx)
+ Mpx->Remove (*s);
+}
+
+/*?
+The implementation of \fun{UchChannel::HandleRead}.
+The server accepts the incoming conncetion and calls \fun{CreateClient}
+to instantiate the new client.
+?*/
+void
+UchTextServer :: HandleRead ()
+{
+ if (! ok)
+ return;
+ // can't use UchChannel::Accept or SOCKET::SockAccept
+ // (should change their interface)
+ int fd = accept (FilDes (), 0, 0);
+ if (fd < 0) {
+ SysError (ErrWarn, "UchTextServer::Accept");
+ return;
+ }
+ CreateClient (fd);
+}
+
+/*?
+This protected function creates a new client on file descriptor \var{fd}.
+The client is instantiated by calling the function registered with the
+server when it was created (see the constructor).
+The new client is registered with the multiplexer, it is added to the client
+list, and its \fun{Starting} virtual member is called so that it can
+performed its initialization.
+?*/
+UchTextClient*
+UchTextServer :: CreateClient (int fd)
+{
+ UchTextClient* cl = (*newClient) (this);
+ if (! cl)
+ return 0;
+ cl->UchChannel::Open (fd);
+
+ cl->SetMode (IORead);
+ if (Mpx)
+ Mpx->Add (*cl);
+
+ // link client list
+ Clients.Append (cl);
+
+ // tell the client that it is running
+ cl->Starting ();
+
+ return cl;
+}
+
+//---------------- UchTextClient
+
+/*?
+The constructor for a new client of server \var{s}.
+?*/
+UchTextClient :: UchTextClient (UchTextServer* s)
+: UchTextStream (),
+ MyServer (s)
+{
+ sendToOut = FALSE;
+ out = 0;
+}
+
+/*?
+The destructor of a client does nothing.
+It is protected.
+Clients are deleted automatically when nobody references them.
+Normally, calling \fun{Close} should delete a client.
+?*/
+UchTextClient :: ~UchTextClient ()
+{
+}
+
+/*?
+This protected virtual function is called by the server when
+the client has been instantiated and successfully registered.
+By default it does nothing.
+?*/
+void
+UchTextClient :: Starting ()
+{
+ // nothing
+}
+
+/*?
+This protected virtual function is called by \fun{HandleRead} when
+an end-of-file is read (the argument is then TRUE) or when an error occured
+while reading (the argument is then FALSE).
+It calls the server's \fun{Remove} function for this client,
+which should result in the destruction of the client.
+This virtual function can be redefined in derived classes, but the
+redefinition should call the default implementation.
+?*/
+void
+UchTextClient :: Closing (bool)
+{
+ MyServer->Remove (this);
+}
+
+/*?
+This protected virtual function is called by the server when it is closing down.
+The default implementation does nothing.
+?*/
+void
+UchTextClient :: Quitting ()
+{
+ // nothing
+}
+
+/*?
+This is the implementation of the virtual function \fun{UchTextStream::DoSend}.
+If the output of the client has been redirected with \var{SetOutput},
+the output buffer is written to this output, or is discarded if no
+output channel is defined.
+If the output has not been redirected, the output buffer is written
+on the client's channel.
+?*/
+void
+UchTextClient :: DoSend ()
+{
+ if (sendToOut) {
+ if (out)
+ out->Write (OutBuffer);
+ else
+ OutBuffer.Flush ();
+ } else
+ Write (OutBuffer);
+}
+
+/*?
+This is the implementation of the virtual function \fun{UchTextStream::Quit},
+which is called when a \com{Quit} request is received.
+It calls the server's \fun{Quit} function.
+?*/
+void
+UchTextClient :: Quit ()
+{
+ if (MyServer)
+ MyServer->Quit ();
+}
+
+/*?
+This is the implementation of the virtual function \fun{UchTextStream::Close},
+which is called when a \com{Close} request is received.
+It calls the server's \fun{Remove} function for this client.
+?*/
+void
+UchTextClient :: Close ()
+{
+ if (MyServer)
+ MyServer->Remove (this);
+}
+
+/*?
+Redirect the output to channel \var{ch}.
+If \var{ch} is 0, output is simply discarded.
+?*/
+void
+UchTextClient :: SetOutput (UchChannel* ch)
+{
+ sendToOut = TRUE;
+ out = ch;
+}
+
+/*?
+Reset the output to the client's channel.
+?*/
+void
+UchTextClient :: ResetOutput ()
+{
+ out = 0;
+ sendToOut = FALSE;
+}
+