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/TclAgent.cc | 298 +++++++++++++++++++++++++++++++++++++++++++ comm/OLD/TextServer.cc | 337 +++++++++++++++++++++++++++++++++++++++++++++++++ comm/OLD/TextServer.h | 93 ++++++++++++++ comm/SignalHandler.cc | 56 ++++++++ comm/SignalHandler.h | 46 +++++++ 5 files changed, 830 insertions(+) create mode 100644 comm/OLD/TclAgent.cc create mode 100644 comm/OLD/TextServer.cc create mode 100644 comm/OLD/TextServer.h create mode 100644 comm/SignalHandler.cc create mode 100644 comm/SignalHandler.h diff --git a/comm/OLD/TclAgent.cc b/comm/OLD/TclAgent.cc new file mode 100644 index 0000000..a72bee0 --- /dev/null +++ b/comm/OLD/TclAgent.cc @@ -0,0 +1,298 @@ +/* + * The Unix Channel + * + * by Michel Beaudouin-Lafon + * + * Copyright 1990-1993 + * Laboratoire de Recherche en Informatique (LRI) + * + * An extension to Tcl for using agents + * + * $Id$ + * $CurLog$ + */ + +#include "TextStream.h" +#include "ccu/String.h" +#include "TkMultiplexer.h" +#include +#include + +extern "C" { +#include +} +#undef const + +class TclAgent : public UchTextService { +public: + TclAgent (Tcl_Interp*, const char*); + ~TclAgent (); + + void SetGotServerCmd (const char*); + void SetLostServerCmd (const char*); + void SetAbandonCmd (const char*); + void SetClosingCmd (const char*); +inline const char* GetName () const { return tclName; } + + +protected: + CcuString tclName; + Tcl_Interp* interp; + CcuString gotServerCmd; + CcuString lostServerCmd; + CcuString abandonCmd; + + Tcl_CmdBuf buffer; + + cmd_res Execute (const UchTextLine&); + void LostServer (); + void GotServer (); + void AbandonRestart (); +}; + + +TclAgent :: TclAgent (Tcl_Interp* i, const char* nm) +: UchTextService (), + tclName (nm), + gotServerCmd (), + lostServerCmd (), + abandonCmd () +{ + interp = i; + buffer = Tcl_CreateCmdBuf (); +} + +void +TclAgent :: SetGotServerCmd (const char* cmd) +{ + gotServerCmd = cmd; +} + +void +TclAgent :: SetLostServerCmd (const char* cmd) +{ + lostServerCmd = cmd; +} + +void +TclAgent :: SetAbandonCmd (const char* cmd) +{ + abandonCmd = cmd; +} + +TclAgent :: ~TclAgent () +{ + Tcl_DeleteCmdBuf (buffer); +} + +/* + * eval the following command: + * catch { agentname.cmd args } + * where cmd is the first word of the line, i.e. the reply sent by the agent + * and agentname the name of the agent as defined with the 'agent' command. + * catch allows to handle undefined handlers for replies gracefully. + */ +UchTextStream::cmd_res +TclAgent :: Execute (const UchTextLine& line) +{ + char buf [1024]; + char* p; + + + sprintf (buf, "catch { %s.%s ", tclName, (const char*) (line [0])); + p = buf + strlen (buf); + + for (int i = 1; i < line.NumWords (); i++) { + if (line[i].IsInt ()) + sprintf (p, "%d ", int (line[i])); + else + sprintf (p, "{%s} ", (const char*) (line[i])); + p += strlen (p); + } + strcpy (p, "}"); + + if (Tcl_GlobalEval (interp, buf) == TCL_OK) + return isCmdOk; + return isCmdError; +} + +void +TclAgent :: LostServer () +{ + UchTextService::LostServer (); + + if (lostServerCmd) + Tcl_GlobalEval (interp, (char*)(const char*)lostServerCmd); +} + +void +TclAgent :: GotServer () +{ + UchTextService::GotServer (); + + if (gotServerCmd) + Tcl_GlobalEval (interp, (char*)(const char*)gotServerCmd); +} + +void +TclAgent :: AbandonRestart () +{ + if (abandonCmd) + Tcl_GlobalEval (interp, (char*)(const char*) abandonCmd); + + Tcl_DeleteCommand (interp, (char*)(const char*) tclName); + CloseNow (); +} + +//---------------- Tcl commands + +/* + * command to send requests to an agent and to operate an agent + * agentname send request args... + * agentname status + * returns unavailable, error, running, lost + * agentname close + * agentname closenow + */ +int +AgentCmd (ClientData data, Tcl_Interp* interp, int argc, char* argv []) +{ + TclAgent* agent = (TclAgent*) data; + + /* check arguments: at least two */ + if (argc < 2) { + Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0], + " status | close | closenow | send request [args ...]\"", (char *) NULL); + return TCL_ERROR; + } + + const char* cmd = argv [1]; + + /* send command */ + if (strcmp (cmd, "send") == 0) { + if (argc < 3) { + Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0], + " send request [args ...]\"", (char *) NULL); + return TCL_ERROR; + } + + for (int i = 2; i < argc; i++) { + agent->Append (argv [i]); + if (i < argc -1) + agent->Append (" "); + } + agent->Send ("\n"); + return TCL_OK; + } + + /* simple commands */ + if (argc != 2) { + Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0], + " status | close | closenow | send request [args ...]\"", (char *) NULL); + return TCL_ERROR; + } + + if (strcmp (cmd, "status") == 0) { + switch (agent->GetStatus ()) { + case UchTextService::isUnavailable: + sprintf (interp->result, "unavailable"); + break; + case UchTextService::isError: + sprintf (interp->result, "error"); + break; + case UchTextService::isRunning: + sprintf (interp->result, "running"); + break; + case UchTextService::isLost: + sprintf (interp->result, "lost"); + break; + } + } else if (strcmp (cmd, "close") == 0) { + Tcl_DeleteCommand (interp, (char*) agent->GetName ()); + agent->Close (); + } else if (strcmp (cmd, "closenow") == 0) { + Tcl_DeleteCommand (interp, (char*) agent->GetName ()); + agent->CloseNow (); + } else { + Tcl_AppendResult(interp, "bad option name: \"", cmd, + "\"", (char *) NULL); + return TCL_ERROR; + } + + return TCL_OK; +} + +/* + * command to create a new agent: + * agent name [-option value ...] + */ +int +CreateAgentCmd (ClientData, Tcl_Interp* interp, int argc, char* argv []) +{ + TclAgent* agent; + + /* check arguments: at least two, and even number overall */ + if (argc < 2 || (argc & 01) != 0) { + Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0], + " name [-option value ...]\"", (char *) NULL); + return TCL_ERROR; + } + + char* name = argv [1]; + char* host = 0; + agent = new TclAgent (interp, name); + + for (int i = 2; i < argc; i++) { + char* option = argv [i++]; + char* value = argv [i]; + if (strcmp (option, "-host") == 0) + host = value; + else + if (strcmp (option, "-name") == 0) + name = value; + else + if (strcmp (option, "-init") == 0) + agent->SetGotServerCmd (value); + else + if (strcmp (option, "-lost") == 0) + agent->SetLostServerCmd (value); + else + if (strcmp (option, "-abandon") == 0) + agent->SetAbandonCmd (value); + else { + Tcl_AppendResult(interp, "bad option name: \"", argv[i-1], + "\"", (char *) NULL); + return TCL_ERROR; + } + } + + agent->Init (name, host); + + /* define the command for manipulating the source */ + Tcl_CreateCommand (interp, name, AgentCmd, (ClientData) agent, 0); + + return TCL_OK; +} + +//---------------- initialization + +/* + * initialize the audio gizmo + * returns 0 if error and leaves the message in interp->result + */ +UchTkMultiplexer mpx; + +extern "C" int +InitAgent (Tcl_Interp* interp) +{ + Tcl_CreateCommand (interp, "agent", CreateAgentCmd, 0, 0); + + return 1; +} + +extern "C" int tkmain (int, char* []); + +main (int argc, char* argv []) +{ + return tkmain (argc, argv); +} 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; +} + diff --git a/comm/OLD/TextServer.h b/comm/OLD/TextServer.h new file mode 100644 index 0000000..ad64b2a --- /dev/null +++ b/comm/OLD/TextServer.h @@ -0,0 +1,93 @@ +/* + * The Unix Channel + * + * by Michel Beaudouin-Lafon + * + * Copyright 1990-1993 + * Laboratoire de Recherche en Informatique (LRI) + * + * Text-oriented servers + * + * $Id$ + * $CurLog$ + */ + +#ifndef TextServer_H_ +#define TextServer_H_ + +#include "TextStream.h" +#include "ccu/List.h" + +class UchTextClient; +class UchTextServer; +class UchBaseMultiplexer; + +/* a function that instantiates clients */ +typedef UchTextClient* (*fNEW_CLIENT) (UchTextServer*); + + +class UchTextServer : public UchStream { +friend class UchTextClient; +friend class UchTextServerTimer; + +protected: + UchTextServerTimer* Timer; // periodic registration with port server + bool ok; // true if initialized +#ifndef CPLUS_BUG19 + CcuListOf Clients; // Clients created by this server +#else + CcuList Clients; // Clients created by this server +#endif + const char* service; // name of service in portserv + fNEW_CLIENT newClient; // function that creates the client + + void Remove (UchTextClient*); // called from UchTextClient + void HandleRead (); + +public: + UchTextServer (const char*, fNEW_CLIENT); + ~UchTextServer (); + bool Ok () const { return ok; } + bool Init (UchBaseMultiplexer&); // initialize the communication stuff + void Quit (); // close the server and its connections + UchTextClient* CreateClient (int); +}; + +PointerClass (pUchTextServer, UchTextServer) + +class UchTextClient : public UchTextStream { +friend class UchTextServer; + +protected: + pUchTextServer MyServer; // who created me + bool sendToOut; // whether to use alternate output + pUchChannel out; // alternate output + + UchTextClient (UchTextServer*); // called by UchTextServer::HandleRead + ~UchTextClient (); // called by UchMultiplexer::Remove +virtual void Starting (); // called by UchTextServer +virtual void Closing (bool); // called by UchTextServer +virtual void Quitting (); // called by UchTextServer + void DoSend (); + + cmd_res Execute (const UchTextLine&) = 0; + +public: + void Close (); // 'close' request + void Quit (); // 'quit' request + + void SetOutput (UchChannel*); + void ResetOutput (); + UchChannel* GetOutput () { if (sendToOut) return out; else return this; } +}; + + + +#endif /*TextServer_H_*/ + + + + + + + diff --git a/comm/SignalHandler.cc b/comm/SignalHandler.cc new file mode 100644 index 0000000..1315812 --- /dev/null +++ b/comm/SignalHandler.cc @@ -0,0 +1,56 @@ +/* + * The Unix Channel + * + * by Michel Beaudouin-Lafon and Stephane Chatty + * + * Copyright 1990-1993 + * Laboratoire de Recherche en Informatique (LRI) + * Centre d'Etudes de la Navigation Aerienne + * + * Multiplexer-based signal handlers + * + * $Id$ + * $CurLog$ + */ + +#include "Signal.h" +#include "Multiplexer.h" + +UchBaseSignalHandler :: UchBaseSignalHandler (UchBaseMultiplexer& m, int sig) +: CcuBaseSignalHandler (sig), + MyMpx (m) +{ +} + +UchBaseSignalHandler :: ~UchBaseSignalHandler () +{ +} + + +void +UchBaseSignalHandler :: Handle () +{ + MyMpx.HandleSignal (*this); +} + +void +UchBaseSignalHandler :: DeferredHandle (int) +{ +} + +UchSignalHandler :: UchSignalHandler (UchBaseMultiplexer& m, int sig, void (*h) (int, int)) +: UchBaseSignalHandler (m, sig), + Handler (h) +{ +} + +UchSignalHandler :: ~UchSignalHandler () +{ +} + + +void +UchSignalHandler :: DeferredHandle (int nb) +{ + (*Handler) (Signal, nb); +} diff --git a/comm/SignalHandler.h b/comm/SignalHandler.h new file mode 100644 index 0000000..f5a7b05 --- /dev/null +++ b/comm/SignalHandler.h @@ -0,0 +1,46 @@ +/* + * The Unix Channel + * + * by Michel Beaudouin-Lafon and Stephane Chatty + * + * Copyright 1990-1993 + * Laboratoire de Recherche en Informatique (LRI) + * Centre d'Etudes de la Navigation Aerienne + * + * Multiplexer-based signal handlers + * + * $Id$ + * $CurLog$ + */ + +#ifndef UchSignal_H_ +#define UchSignal_H_ + +#include "ccu/Signal.h" + +class UchBaseSignalHandler : public CcuBaseSignalHandler { +friend class UchBaseMultiplexer; + +protected: + UchBaseMultiplexer& MyMpx; + void Handle (); +virtual void DeferredHandle (int); + +public: + UchBaseSignalHandler (UchBaseMultiplexer&, int); +virtual ~UchBaseSignalHandler (); +}; + +class UchSignalHandler : public UchBaseSignalHandler { +protected: + void (*Handler) (int, int); + void DeferredHandle (int); + +public: + UchSignalHandler (UchBaseMultiplexer&, int, void (*) (int, int)); + ~UchSignalHandler (); +}; + +#endif /* UchSignal_H_ */ + + -- cgit v1.1