summaryrefslogtreecommitdiff
path: root/comm/OLD/Agent.cc
diff options
context:
space:
mode:
Diffstat (limited to 'comm/OLD/Agent.cc')
-rw-r--r--comm/OLD/Agent.cc386
1 files changed, 386 insertions, 0 deletions
diff --git a/comm/OLD/Agent.cc b/comm/OLD/Agent.cc
new file mode 100644
index 0000000..3e4bf8a
--- /dev/null
+++ b/comm/OLD/Agent.cc
@@ -0,0 +1,386 @@
+/*
+ * The Unix Channel
+ *
+ * by Michel Beaudouin-Lafon
+ *
+ * Copyright 1990-1993
+ * Laboratoire de Recherche en Informatique (LRI)
+ *
+ * Agents, by Stephane Chatty
+ *
+ * $Id$
+ * $CurLog$
+ */
+
+#include "Agent.h"
+
+/*?class UchAgent
+The class \typ{UchAgent} derives from \typ{UchStream}.
+It is associated to a channel set to monitor the connected agents in parallel.
+Whenever a new agent connects, the virtual function \fun{HandleNew} is called.
+This function must return a pointer to an object of class \typ{UchRemoteAgent}.
+
+Because the agents may be on different machines with different architectures,
+the byte swapping is always done by the ``server'' (ie. the agent that did not initiate
+the communication), by convention. (NOTE: byte swapping is not currently implemented)
+?*/
+
+/*?class UchRemoteAgent
+Class \typ{UchRemoteAgent} derives from \typ{UchMsgStream}.
+It is still an abstract class because the virtual functions \fun{NewMessage} and \fun{ConvertAnswer}
+of \typ{UchMsgStream} are not defined in \typ{UchRemoteAgent}.
+Instances of \fun{UchRemoteAgent} only know that they may belong to an instance of \typ{UchAgent}.
+Thus the virtual function \fun{Delete} is redefined to achieve a clean removal from the server's list.
+?*/
+
+/*?
+Construct an empty server port.
+?*/
+UchAgent :: UchAgent ()
+: UchStream (),
+ RemoteAgents (),
+ ChanSet (0)
+{
+}
+
+/*?nodoc?*/
+UchAgent :: UchAgent (const UchAgent& sp)
+: UchStream (sp),
+ RemoteAgents (),
+ ChanSet (0)
+{
+}
+
+/*?
+Construct a server port bound to address \var{a}.
+When using Internet domain addresses, \var{a} should refer to
+the wildcard address so that clients can connect from any machine.
+This can be done with the instruction \com{new UchInetAddress(ANYADDR)}.
+?*/
+UchAgent :: UchAgent (UchAddress* a)
+: UchStream (a, 0),
+ RemoteAgents (),
+ ChanSet (0)
+{
+}
+
+/*?nodoc?*/
+UchAgent :: ~UchAgent ()
+{
+ UchRemoteAgent* cl = 0;
+
+ while (cl = RemoteAgents.First ())
+ cl->Delete ();
+ ChanSet = 0; // will delete it if necessary
+}
+
+/*?nodoc?*/
+UchChannel*
+UchAgent :: Copy () const
+{
+ return new UchAgent (*this);
+}
+
+/*?
+Remove a client from the set of clients connected to the server.
+This is normally done automatically whenever the client disconnects itself,
+as a side effect of destroying the client.
+?*/
+void
+UchAgent :: RemoveRemoteAgent (UchRemoteAgent* cl)
+{
+ if (RemoteAgents.Remove (cl)) {
+ cl->MyLocalAgent = 0;
+ HandleRemove (cl);
+ } else
+ Error (ErrWarn, "UchAgent::RemoveRemoteAgent", "not owned by this server");
+}
+
+/*?
+Bind the socket and listen to it.
+Initialize the channel set of the server to \var{cs}, or create a new one if \var{cs} is 0.
+The channel set is used by the server to read and process messages from its clients:
+whenever a client connects to the server, an instance of \typ{UchRemoteAgent} is added to the channel set.
+Whenever data is readable from a client, it is read in an input buffer and processed as soon
+as a full message is received.
+Whenever a client closes the connection, it is removed from the channel set of the server.
+This function returns TRUE if all went well, else it calls \fun{SysError} and returns FALSE.
+You may want to pass your own channel set if you are already multiplexing
+i/o on that channel set. For instance, you may have several \typ{UchAgent} objects
+in your application.
+A smart pointer to the channel set is actually kept in the server, so that it can be shared
+securely.
+?*/
+bool
+UchAgent :: Setup (UchMultiplexer* cs)
+{
+ if (Listen () < 0) {
+ SysError (ErrWarn, "UchAgent::Setup");
+ return FALSE;
+ }
+ SetMode (IORead);
+ if (!cs)
+ cs = new UchMultiplexer;
+ ChanSet = cs;
+ ChanSet->Add (this);
+
+ return TRUE;
+}
+
+/*?
+This function removes the agent's registration channel from its channel set.
+This has the effect of ignoring any incoming connections.
+This function will also make \fun{Run} exit if there is no other
+channel in the channel set.
+Unless you added your own channels to this channel set,
+this will be the case if there is no remote agent currently connected.
+This is the only way to exit properly from \fun{Run}.
+?*/
+void
+UchAgent :: Unlisten ()
+{
+ if (ChanSet)
+ ChanSet->Remove (*this);
+}
+
+
+/*?nodoc?*/
+void
+UchAgent :: HandleRead ()
+{
+// cannot redefine Accept to return UchRemoteAgent*, so this does not work :
+// UchRemoteAgent* cl = Accept ();
+// need to delete the channel created by Accept, so this does not work either :
+// UchRemoteAgent* cl = new UchRemoteAgent (Accept ());
+// so we do this (less elegant ...) :
+ UchChannel* ch = Accept ();
+ if (! ch) {
+ SysError (ErrWarn, "UchAgent::HandleRead: Accept");
+ return;
+ }
+ UchRemoteAgent* ra = new UchRemoteAgent (this, ch);
+ delete ch;
+
+ ra->SetMode (IOReadSelect);
+ RemoteAgents.Append (ra);
+ if (ChanSet)
+ ChanSet->Add (ra);
+}
+
+/*?
+This virtual function is called whenever a new agent connects to this one.
+?*/
+void
+UchAgent :: HandleNew (UchRemoteAgent*)
+{
+}
+
+/*?
+This virtual function is called whenever a remote agent is removed (\fun{RemoveRemoteAgent}).
+It is a hook for the application to take whatever action; the default action is to do nothing.
+When this function is called, the client is already removed from the client list of the server.
+?*/
+void
+UchAgent :: HandleRemove (UchRemoteAgent*)
+{
+}
+
+// default error functions
+//
+/*?nextdoc?*/
+bool
+UchAgent :: SysError (errtype how, const char* who, int excl1, int excl2)
+{
+ return ::SysError (how, who, excl1, excl2);
+}
+
+/*?
+Each server port class can have its own error handling routines.
+Their default action is to call the global functions \fun{Error} and \fun{SysError}.
+They can be called from the following functions:
+\fun{Error} can be called from
+\fun{RemoveRemoteAgent} when the client does not belong to this server;
+\fun{SysError} can be called from
+\fun{Setup} when the socket could not be setup correctly,
+and from \fun{HandleRead}
+when the connection could not be accepted.
+?*/
+void
+UchAgent :: Error (errtype how, const char* who, const char* what)
+{
+ ::Error (how, who, what);
+}
+
+/*?
+Setup the server if necessary, then scan and process its channel set
+by calling \fun{LoopScan} for it.
+To have a server active, you need at least to initialize it (and thus know its address),
+and then run it.
+If you have added your own channels to the channel set of the server,
+their \fun{HandleRead} and \fun{HandleWrite} functions will be called normally by \fun{Run}.
+?*/
+void
+UchAgent :: Run ()
+{
+ if (! ChanSet)
+ if (! Setup ())
+ Error (ErrFatal, "UchAgent::Run", "could not setup");
+ if (ChanSet)
+ ChanSet->LoopScan ();
+}
+
+/*?
+Send a message to all the agents currently connected to this one.
+If \var{flush} is TRUE, the output buffer of each remote agent is flushed.
+?*/
+void
+UchAgent :: Broadcast (UchMessage& msg, bool flush)
+{
+ CcuListIterOf <UchRemoteAgent> li (RemoteAgents);
+ while (++li)
+ (*li)->Send (msg, flush);
+}
+
+/*?
+Send a message to all the agents currently connected to this one, except \var{exclude}.
+If \var{flush} is TRUE, the output buffer of each client is flushed.
+?*/
+void
+UchAgent :: Broadcast (UchMessage& msg, UchRemoteAgent* excl, bool flush)
+{
+ CcuListIterOf <UchRemoteAgent> li (RemoteAgents);
+ while (++li)
+ if (*li != excl)
+ (*li)->Send (msg, flush);
+}
+
+/*?nextdoc?*/
+void
+UchAgent :: Broadcast (UchMsgBuffer& buf, bool flush)
+{
+ CcuListIterOf <UchRemoteAgent> li (RemoteAgents);
+ while (++li)
+ (*li)->Send (buf, flush);
+}
+
+/*?
+These functions are similar to the previous ones, except that they take
+a buffer instead of a message. The buffer {\em must} contain a converted message.
+It is more efficient to broadcast a buffer than a message because there is less
+message conversion overhead.
+?*/
+void
+UchAgent :: Broadcast (UchMsgBuffer& buf, UchRemoteAgent* excl, bool flush)
+{
+ CcuListIterOf <UchRemoteAgent> li (RemoteAgents);
+ while (++li)
+ if (*li != excl)
+ (*li)->Send (buf, flush);
+}
+
+#ifdef DOC
+//fake entries for inline functions
+
+/*?
+Return the channel set used by the server.
+This is useful if you want to add your own channels to the channel set.
+?*/
+UchMultiplexer*
+UchAgent :: GetChanSet ()
+{
+}
+#endif
+
+UchRemoteAgent*
+UchAgent :: Contact (UchAddress* a)
+{
+ if (!a)
+ return 0;
+ UchRemoteAgent* ra = new UchRemoteAgent (this, a);
+ if (ra)
+ ChanSet->Add (ra);
+ return ra;
+}
+
+/*?nodoc?*/
+UchRemoteAgent :: UchRemoteAgent (UchAgent* a)
+: UchMsgStream (),
+ MyLocalAgent (a)
+{
+}
+
+/*?nodoc?*/
+UchRemoteAgent :: UchRemoteAgent (const UchRemoteAgent& cl)
+: UchMsgStream (cl),
+ MyLocalAgent (cl.MyLocalAgent)
+{
+}
+
+/*?
+Construct a new agent connected to this one on channel \var{ch}.
+?*/
+UchRemoteAgent :: UchRemoteAgent (UchAgent* a, UchChannel* ch)
+: UchMsgStream (),
+ MyLocalAgent (a)
+{
+ UchChannel::Open (ch->FilDes ());
+}
+
+UchRemoteAgent :: UchRemoteAgent (UchAgent* a, UchAddress* addr)
+: UchMsgStream (addr, 0),
+ MyLocalAgent (a)
+{
+}
+
+
+/*?nodoc?*/
+UchRemoteAgent :: ~UchRemoteAgent ()
+{
+ if (MyLocalAgent) {
+ UchAgent* s = MyLocalAgent;
+ s->Error (ErrWarn, "~UchRemoteAgent", "remote agent still connected; deleting anyway ...\n");
+ s->RemoveRemoteAgent (this);
+ if (s->ChanSet)
+ s->ChanSet->Remove (*this); // calls the destructor if no more refs
+ }
+}
+
+/*?nodoc?*/
+UchChannel*
+UchRemoteAgent :: Copy () const
+{
+ return new UchRemoteAgent (*this);
+}
+
+/*?
+This function must be used to delete a remote agent explicitly.
+It is not safe to use the operator delete.
+This function is called when an end of file is read from the client;
+this means that you usually do not need to call it.
+?*/
+void
+UchRemoteAgent :: Delete ()
+{
+ if (MyLocalAgent) {
+ UchAgent* s = MyLocalAgent;
+ s->RemoveRemoteAgent (this);
+ if (s->ChanSet)
+ s->ChanSet->Remove (*this); // calls the destructor if no more refs
+ }
+}
+
+
+
+#ifdef DOC
+//fake entries for inline functions
+
+/*?
+Return the server corresponding to a given client.
+?*/
+UchAgent*
+UchRemoteAgent :: GetAgent ()
+{
+}
+
+#endif /* DOC */
+