From e0b1bf56fae7f31706067564527156644a7a5fc2 Mon Sep 17 00:00:00 2001 From: chatty Date: Tue, 27 Jul 1993 13:54:59 +0000 Subject: Initial revision --- comm/OLD/TextServer.cc | 337 +++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 337 insertions(+) create mode 100644 comm/OLD/TextServer.cc (limited to 'comm/OLD/TextServer.cc') 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 + +/* 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 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; +} + -- cgit v1.1