summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorsc2000-12-30 22:45:48 +0000
committersc2000-12-30 22:45:48 +0000
commit5e1dff9dbae47f74232a9f775f799c75b4980d3a (patch)
tree75ee85192eb667355151721eb90089fe0a01af9d
parentc5145a7ea08d606db251360b8722778403205c30 (diff)
downloadivy-league-5e1dff9dbae47f74232a9f775f799c75b4980d3a.zip
ivy-league-5e1dff9dbae47f74232a9f775f799c75b4980d3a.tar.gz
ivy-league-5e1dff9dbae47f74232a9f775f799c75b4980d3a.tar.bz2
ivy-league-5e1dff9dbae47f74232a9f775f799c75b4980d3a.tar.xz
Initial revision, created from bits of TextStream.cc
-rw-r--r--comm/OLD/TextService.cc437
1 files changed, 437 insertions, 0 deletions
diff --git a/comm/OLD/TextService.cc b/comm/OLD/TextService.cc
new file mode 100644
index 0000000..7ba37ba
--- /dev/null
+++ b/comm/OLD/TextService.cc
@@ -0,0 +1,437 @@
+/*
+ * The Unix Channel
+ *
+ * by Michel Beaudouin-Lafon
+ *
+ * Copyright 1990-1993
+ * Laboratoire de Recherche en Informatique (LRI)
+ *
+ * Text services
+ *
+ * $Id$
+ * $CurLog$
+ */
+
+#include "TextService.h"
+#include "TimeOut.h"
+#include "PortServer.h"
+#include "error.h"
+#include <stdlib.h>
+#include <string.h>
+#include <stdio.h>
+#include <ctype.h>
+
+
+//---------------- constants
+
+// we start with a few quick retries
+// AbandonRetries doubles the time and decrement the retries until 1
+// 2 secs * 5 = 10 secs
+// 4 secs * 4 = 16 secs
+// 8 secs * 3 = 24 secs
+// 16 secs * 2 = 32 secs
+// 32 secs * 1 = 32 secs
+// total = 15 retries in 114 secs ~ 2 minutes
+// we want this to be significantly longer than the REG_TIME of the port server
+
+#define RETRY_TIME 2
+#define MAX_RETRIES 5
+
+//---------------- ServiceStarter
+
+class UchServiceStarter : public UchBaseTimeOut {
+friend class UchTextService;
+
+protected:
+ UchTextService* Service;
+ int Retries;
+ int Max;
+
+public:
+ UchServiceStarter (UchTextService*, int, int);
+ void Handle (Millisecond);
+};
+
+UchServiceStarter :: UchServiceStarter (UchTextService* s, int retry, int maxr)
+: UchBaseTimeOut (*s->GetMultiplexer (), retry * 1000),
+ Service (s),
+ Retries (0),
+ Max (maxr)
+{
+}
+
+void
+UchServiceStarter :: Handle (Millisecond)
+{
+ /* UchServiceStarters are not timers triggered on signals.
+ For that reason, Handle is allowed to be complex. */
+
+ if (! Service)
+ return;
+
+ fprintf (stderr, "ServiceStarter::TimeOut, attempting restart\n");
+ if (Service->GetStatus () == UchTextService::isRunning
+ || Service->Restart () == UchTextService::isRunning) {
+ Stop ();
+ Service->Starter = 0;
+ delete this;
+ return;
+ }
+
+ if (++Retries >= Max) {
+ Stop ();
+ if (Max <= 1) {
+ fprintf (stderr, "ServiceStarter::TimeOut, abandoning restart\n");
+ Service->Starter = 0;
+ Service->AbandonRestart ();
+ delete this;
+ } else {
+ Max--;
+ Retries = 0;
+ ChangePeriod (GetPeriod () * 2);
+ Restart ();
+ }
+ }
+}
+
+
+/*?
+Construct an empty \var{UchTextService}.
+When using this constructor, the application must call \fun{Init} at a later
+time in order to define the server to connect to.
+The initial state of the service is \var{isLost}, since the actual
+connection to the server is not established yet.
+?*/
+UchTextService :: UchTextService ()
+: UchTextStream (),
+ StatusFlag (isLost),
+ Starter (0),
+ Closed (false),
+ User (),
+ Service (),
+ Host ()
+{
+}
+
+/*?
+Construct a \var{UchTextService} connected to server \var{s} on host \var{h}.
+This is equivalent to the empty constructor followed by a call to \fun{Init}.
+?*/
+UchTextService :: UchTextService (UchBaseMultiplexer& mpx, const char* s, const char* h)
+: UchTextStream (),
+ StatusFlag (isLost),
+ Starter (0),
+ Closed (false),
+ User (),
+ Service (),
+ Host ()
+{
+ Init (mpx, s, h);
+}
+
+/*?
+The (protected) destructor.
+Call \fun{Close} or \fun{CloseNow} to close down the connection and
+delete the service.
+?*/
+UchTextService :: ~UchTextService ()
+{
+ if (Starter)
+ delete Starter;
+}
+
+/*?
+This protected virtual function is called by \fun{UchTextStream::HandleRead}
+when an end-of-file is read or when a read failed.
+It calls \var{LostServer} so that an attempt to reconnect to the server
+can be made.
+?*/
+void
+UchTextService :: Closing (bool)
+{
+ fprintf (stderr, "UchTextService::Closing, lost server\n");
+ StatusFlag = isLost;
+ LostServer ();
+}
+
+/*?
+Attempt to connect to the server.
+If the address of the server cannot be retrieved from the port server,
+this function sets the state of the service to \var{isUnavailable}
+and returns.
+If an address is obtained from the port server, this function tries to connect
+to that address.
+If this fails, it sets the state to \var{isError} and returns.
+Otherwise, it sets the state to \var{isRunning} and calls the virtual
+function \fun{GotServer}.
+The service is automatically registered with the multiplexer, with mode \var{IONone}
+the first time the connection is established.
+?*/
+UchTextService::status
+UchTextService :: Restart ()
+{
+ UchInetAddress* addr = PortServerInquire ("portserv", Service, Host);
+ if (! addr) {
+#if 0
+ // *** horrible patch - see portcli.C. This info should be returned by PortServerInquire
+ extern bool PortServerInquireSysError;
+ if (PortServerInquireSysError) {
+ Log ("TSERVICE::Restart", "no agent manager");
+ return StatusFlag = isError;
+ }
+#endif
+ fprintf (stderr, "UchTextService::Restart, no address in port server\n");
+ return StatusFlag = isUnavailable;
+ }
+ if (addr->Host () == 0 && addr->Port () == 0) {
+// Log ("TSERVICE::Restart", "agent being launched by agent manager");
+ return StatusFlag = isLost;
+ }
+
+ ConnectTo (addr);
+
+ bool wasopened = Fd.Opened ();
+ bool setup = true;
+ if (wasopened) {
+ // we are in trouble because a stream socket can be connected
+ // only once and a channel is immutable...
+ // so we have to fake a reopen
+ int ofd = FilDes ();
+ if (ofd >= 0) {
+ close (ofd);
+ int nfd = socket (ConnectedTo () ->Family (), SockType (), 0);
+// fprintf (stderr, "UchTextService::Restart, reopening socket: %d -> %d\n", (void*) ofd, (void*) nfd);
+ if (nfd < 0) {
+ setup = false;
+ } else if (nfd != ofd) {
+ dup2 (nfd, ofd);
+ close (nfd);
+ }
+ }
+ }
+ if (setup)
+ setup = Setup ();
+ if (! wasopened) {
+ SetMode (IONone);
+ if (Mpx)
+ Mpx->Add (this); ///////// Mpx was initialized by Init
+ }
+ if (! setup) {
+ fprintf (stderr, "UchTextService::Restart, could not setup connection\n");
+ return StatusFlag = isError;
+ }
+
+ StatusFlag = isRunning;
+ if (Starter) // do not log if got server at first attempt
+ fprintf (stderr, "UchTextService::Restart, got server\n");
+ GotServer ();
+ return StatusFlag;
+}
+
+/*?
+This protected function arranges for a connection to be attempted in
+\var{retry_time} seconds.
+If the connection cannot be established after \var{maxr} retries,
+\var{retry_time} is doubled and \var{maxr} is decremented and new attempts
+are made with these new values.
+When the number of retries is null, then the virtual function
+\fun{AbandonRestart} is called and no further attempts are made.
+If \var{retry_time} is 0, any pending attempts are cancelled.
+If \var{retry_time} or var{maxr} is negative, suitable default values are used.
+?*/
+void
+UchTextService :: AutoStart (int retry_time, int maxr)
+{
+ if (retry_time < 0)
+ retry_time = RETRY_TIME;
+ if (maxr < 0)
+ maxr = MAX_RETRIES;
+
+ if (retry_time == 0) { // cancel auto-start
+ if (Starter) {
+ delete Starter;
+ Starter = 0;
+ }
+ return;
+ }
+ if (Starter) {
+ Starter->ChangePeriod (retry_time);
+ Starter->Retries = 0;
+ Starter->Max = maxr;
+ } else if (Mpx) {
+ Starter = new UchServiceStarter (this, retry_time, maxr);
+ } else
+ fprintf (stderr, "UchTextService::AutoStart, no multiplexer for time-out\n");
+}
+
+/*?
+This protected virtual function is called when the connection to the server
+has been broken.
+By default, it resets the mode of the channel to \var{IONone} so that the
+multiplexer does not attempt to read from the server.
+Derived classes can redefine this function, but the redefinition should
+call the default implementation.
+?*/
+void
+UchTextService :: LostServer ()
+{
+ Mpx->SetMode (*this, IONone);
+ AutoStart ();
+}
+
+/*?
+This protected virtual function is called when the connection to the server
+has been established.
+By default, it sets the mode of the channel to \var{IORead} so that the
+multiplexer can monitor the channel.
+If the output buffer is not empty, it sends it to the server by calling
+\fun{DoSend}.
+Derived classes can redefine this function, but the redefinition should
+call the default implementation.
+?*/
+void
+UchTextService :: GotServer ()
+{
+ Mpx->SetMode (*this, IORead);
+ if (OutBuffer.BufLength () != 0)
+ Flush ();
+}
+
+/*?
+This protected virtual function is called when the connection cannot
+be restarted (see \fun{AutoStart}).
+By default it calls \fun{CloseNow} which should ultimately destroy the object.
+A derived class can redefine this function to take whatever clean-up action
+is required.
+?*/
+void
+UchTextService :: AbandonRestart ()
+{
+ CloseNow ();
+}
+
+/*?
+This implementation of the protected virtual function \fun{UchTextStream::Execute}
+always return \var{isCmdOk}.
+This is suitable for the global function \var{TellServer}.
+Derived classes generally do redefine this function.
+?*/
+UchTextStream::cmd_res
+UchTextService :: Execute (const UchTextLine&)
+{
+ // just discard received request by default
+ // (suitable for TellServer below)
+ return isCmdOk;
+}
+
+/*?
+This implementation of the protected virtual function \fun{UchBufStream::Flush}
+writes the output buffer only if the state of the connection is
+\var{isRunning}.
+Otherwise, the outgoing requests accumulate in the ouput buffer until the
+connection is established.
+This function also closes down the connection by calling \var{MpxRemoveChannel}
+if \fun{Close} has been called before the connection ws actually established.
+?*/
+void
+UchTextService :: Flush ()
+{
+ if (StatusFlag == isRunning) {
+ Write (OutBuffer);
+ if (Closed)
+ Mpx->Remove (*this);
+ }
+}
+
+/*?
+Define the server and host to connect to. This function must be used
+if the object was constructed with the default constructor.
+If the connection to the server cannot be established, \fun{Init} calls
+\var{AutoStart} to attempt the connection later.
+?*/
+void
+UchTextService :: Init (UchBaseMultiplexer& mpx, const char* s, const char* h)
+{
+ if (StatusFlag == isRunning)
+ return;
+
+ Service = s;
+ Host = h;
+ Mpx = &mpx;
+
+ StatusFlag = Restart ();
+ if (StatusFlag == isError) {
+ // try to run the agent manager
+ if (fork () != 0) {
+ // we are the parent process, and we become the agent manager
+ // *** how to have the agent manager survive the client ???
+ ::Error (ErrLog, "TSERVICE::Init", "trying to run agentman");
+ if (execlp ("agentman", "agentman", 0) != 0)
+ ::Error (ErrWarn, "TSERVICE::Init", "could not run agentman");
+ }
+ }
+ // delay retry
+ if (StatusFlag != isRunning)
+ AutoStart ();
+}
+
+/*?
+Return the current retry time for the auto-restart of the connection.
+If the connection is not in auto-restart mode, return -1;
+?*/
+int
+UchTextService :: GetRetryTime ()
+{
+ return Starter ? Starter->GetPeriod () / 1000 : -1;
+}
+
+/*?
+Return the current maximum number of retries for the auto-restart of the connection.
+If the connection is not in auto-restart mode, return -1;
+?*/
+int
+UchTextService :: GetMaxRetries ()
+{
+ return Starter ? Starter->Max : -1;
+}
+
+/*?
+Remove this service from the multiplexer if the connection is established
+or if the output buffer is empty.
+Otherwise, mark the connection as being closed;
+in this case, the output buffer will be sent when the connection is etablished,
+and then the connection will be closed.
+?*/
+void
+UchTextService :: Close ()
+{
+ Closed = true;
+ if (StatusFlag == isRunning || OutBuffer.BufLength () == 0)
+ Mpx->Remove (*this);
+}
+
+/*?
+Remove this service from the multiplexer, whatever
+the state of the connection is.
+?*/
+void
+UchTextService :: CloseNow ()
+{
+ Mpx->Remove (*this);
+}
+
+#if 0
+/*?
+This global function provides the simplest interface to send a request \var{req}
+to a server \var{sname} on host \var{host}.
+?*/
+bool
+TellServer (const char* sname, const char* host, const char* req)
+{
+ UchTextService* serv = new UchTextService;
+ serv->Init (sname, host);
+ serv->Send (req);
+ serv->Close ();
+ return true;
+}
+#endif