Copyright © 1997 The California Institute of Technology
All rights reserved.

example4.cpp


  1 /*
  2 ** File
  3 **      example4.cpp
  4 **      Copyright 1997, The California Institute of Technology
  5 **
  6 ** Function
  7 **      Subscribe to a file type. Save the session state in the restart file
  8 **      and write files to the directory named in localPath. If an email
  9 **      address is provided, use it when sending messages. Also, messages are
 10 **      sent to a log file in this program. If report times are provided,
 11 **      and email report of newly arrived files will be sent at those times and
 12 **      a final report will be sent when the program terminates normally.
 13 **
 14 ** Creator
 15 **      J. Rector, JPL
 16 **
 17 ** Created
 18 **      June, 1997
 19 **
 20 ** History
 21 **
 22 */
 23 
 24 #include <stdio.h>
 25 #include <errno.h>
 26 #include <string.h>
 27 #include <signal.h>
 28 #include <sys/types.h>
 29 #include <unistd.h>
 30 #include <time.h>
 31 #include <new.h>
 32 #include "Subscription.h"
 33 
 34 // Prototypes
 35 void session (Subscription& notify);
 36 void newlyArrivedFile (const char *string, FeiMailReport *report);
 37 void outOfMemory (void);
 38 void sigHandler (int sig);
 39 void usage (const char *progName);
 40 
 41 
 42 // Signals end of processing when true. See session and sigHandler
 43 // functions for useage.
 44 static bool shutDown = false;
 45 
 46 // FeiMsg buffer and status - used by all functions
 47 static char msg[256];
 48 static int status = FEI_OK;
 49 
 50 
 51 int main (int argc, char *argv[])
 52 {
 53    // Only defined if we end up reporting on subscription files via mail.
 54    FeiMailReport *report = (FeiMailReport *)NULL;
 55 
 56    if (argc < 2) usage (argv[0]);
 57 
 58    // If the first argument is "restart", note that. The value of i is
 59    // an index into the argv array. Set initially to reflect whether or
 60    // not the first argument was "restart".
 61    bool restartFlag = false;
 62    int i = 1;
 63    if (strcmp (argv[1], "restart") == 0)
 64    {
 65       if (argc < 3) usage (argv[0]);
 66       restartFlag = true;
 67       i = 2;
 68    }
 69 
 70    // Create a Subscription session object used for notification. Assume
 71    // that argv[i] has the file type.
 72    Subscription notify (argv[i++]);
 73    if (status = notify.getStatus ())
 74       return status;
 75    notify.setOptions (feiVersion);
 76 
 77    // Set up from command line parameters. Must have file type. If no
 78    // local path, path is current working directory ".". If not email
 79    // address, emailAddr is NULL. If report times and email, the reporting.
 80    const char *localPath =
 81       (argc> i) ? (const char *)argv[i++] : ".";
 82    const char *emailAddr =
 83       (argc > i) ? (const char *)argv[i++] : (const char *)NULL;
 84    // Create a report to be sent to emailAddr using subject contained in msg.
 85    // Reporting times are specified in argv[i].
 86    if (emailAddr && argc > i)
 87       if (!(report = notify.initReport (emailAddr, argv[i])))
 88          return notify.getStatus ();
 89 
 90    // Set up signal handler for SIGINT, SIGTERM. The program responds to the
 91    // signal when the variable 'shutDown' is true. Since SIGTERM is the
 92    // default signal used by kill (at least on Unix systems), you stop
 93    // the program with either <cntrl-c> or the following command:
 94    //      # kill <pid>
 95    {
 96       if (signal (SIGINT, sigHandler) == SIG_ERR ||
 97          signal (SIGTERM, sigHandler) == SIG_ERR)
 98       {
 99          status = FEI_FATAL;
100          sprintf (msg, "Can't setup signal handler. %s", strerror (errno));
101          feiMsg().record (msg, status);
102          return (status);
103       }
104    }
105 
106    // Replace new-handler. Called when memory can't be allocatd by
107    // 'new'.
108    set_new_handler (outOfMemory);
109 
110    // Set up messaging for log, display and email
111    notify.initMessages (emailAddr, true);
112    if (status = notify.getStatus ())
113       return status;
114 
115    // This function either connects and subscribes or restarts if the
116    // file type is "restart" and the name of a valid restart file is
117    // provided. Files received are written directory specified by localPath.
118    if (notify.connectForSubscribe (localPath, restartFlag) > FEI_OK)
119       return (FEI_FATAL);
120 
121    // Now set up a subscription session.
122    session (notify);
123 
124    feiMsg().record ("Normal program termination.\n", FEI_INFO);
125    return (status);
126 }
127 
128 /*
129 ** This is the subscription session loop. We continue in this loop until
130 ** interrupted by a signal. There is logic for testing if we're still
131 ** connected to the server. If the connection is ever lost, we continue
132 ** to try to reconnect. When we can, we use the restart file's state
133 ** to pickup where we left off.
134 ** Note: If we're restarting a subscription we already caught-up before
135 ** we get here.
136 */
137 void session (Subscription& notify)
138 {
139    FeiMailReport *report = notify.getReport ();
140 
141    long delay = 5; // seconds
142    FeiProfile *profile;
143    while (!shutDown)   
144    {
145       // Are we still connected to the server? If not try to reconnect
146       // using the state information in the subscription session's
147       // restart file. Continue to send messages about the state of
148       // this attempt.
149       if (!notify.isConnected ())
150       {
151          notify.reconnect (&shutDown);
152          continue;
153       }
154 
155       // Check to see if we have any new files. If we do, save the
156       // information for reporting at intervals. We use a delay time
157       // with 'result()' to slow down the cycle time for the session
158       // loop.
159       while ((profile = notify.result (delay)) != (FeiProfile *)NULL)
160       {
161          if (profile->getStatus () == FEI_OK)
162             newlyArrivedFile (profile->getProfileString (), report);
163 
164          // Need this so we test in the inner loop as well as the outer loop.
165          // Files can arrive so quickly that the queue always has something
166          // in it and we never leave inner loop in that case.
167          if (shutDown)
168             return;
169       }
170    } // end of sesson loop
171 
172    // Shut down section.
173    // Disconnect from subscription and save any files in the result queue.
174    // Note: We use a short delay for result () here. We want to check
175    // for results in a timely fashion, but at the same time we don't want
176    // to use extra resources because other programs may also be trying
177    // to work or to shutdown.
178    notify.disconnect ();
179 
180    delay = 2;
181    while ((profile = notify.result (delay)) != (FeiProfile *)NULL)
182    {
183       if (profile->getStatus () == FEI_OK)
184          newlyArrivedFile (profile->getProfileString (), report);
185       delete profile;
186    }
187 
188    // Report's destructor will send a final report.
189    if (report)
190       delete report;
191 }
192 
193 /*
194 ** Report information on a newly arrived file. Turn off mail if it's on
195 ** so we don't mail a message each time a file arrives. Use report to
196 ** group that information.
197 */
198 void newlyArrivedFile (const char *string, FeiMailReport *report)
199 {
200    feiMsg().record (string, FEI_INFO);
201    // Are we producing reports of what's been delivered. If so,
202    // add information about the file just received to the report.
203    if (report && report->getStatus () == FEI_OK)
204       report->addToReport (string);
205 }
206 
207 /*
208 ** Executed when program can't allocate memory with 'new'.
209 */
210 void outOfMemory (void)
211 {
212    status = FEI_FATAL;
213    feiMsg().useHeader (false); // headers allocate more memory in heap!
214    feiMsg().record ("Memory allocation error.", status);
215    exit (status);
216 }
217 
218 /*
219 ** Signal handler for SIGTERM. Sets the 'shutDown' flag to true. The next
220 ** time it's tested in function 'session' we begin to shut down saving
221 ** any files already in the queue. If we receive a signal a second time,
222 ** shutdown is immediate.
223 */
224 void sigHandler (int sig)
225 {
226    signal (sig, sigHandler);
227 
228    if (shutDown)
229    {
230       feiMsg().setMailMessage (true);
231       feiMsg().record ("Executing immediate shutdown.\n", FEI_WARN);
232       exit (FEI_OK);
233    }
234    shutDown = true;
235 }
236 
237 /*
238 ** Program usage
239 */
240 void usage (const char *progName)
241 {
242    fprintf (stderr, "\n%s [restart] <file type> [<local path>] ['<email address>' [<report times>]]\n\n", progName);
243    exit (FEI_INFO);
244 }


example4.cpp