OmniEvents
main.cc
Go to the documentation of this file.
1 // Package : omniEvents
2 // main.cc Created : 2004/08/01
3 // Author : Alex Tingle.
4 //
5 // Copyright (C) 1998 Paul Nader, 2004-2005 Alex Tingle.
6 //
7 // This file is part of the omniEvents application.
8 //
9 // omniEvents is free software; you can redistribute it and/or
10 // modify it under the terms of the GNU Lesser General Public
11 // License as published by the Free Software Foundation; either
12 // version 2.1 of the License, or (at your option) any later version.
13 //
14 // omniEvents is distributed in the hope that it will be useful,
15 // but WITHOUT ANY WARRANTY; without even the implied warranty of
16 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
17 // Lesser General Public License for more details.
18 //
19 // You should have received a copy of the GNU Lesser General Public
20 // License along with this library; if not, write to the Free Software
21 // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
22 //
23 // Description:
24 // Event Services Channel Factory implementation. The factory registers
25 // itself with the naming service. Clients wishing to create event
26 // channels can either use the factory by resolving its name with the
27 // naming service or create in-process channels.
28 //
29 
30 #ifdef HAVE_CONFIG_H
31 # include "config.h"
32 #endif
33 
34 #ifdef HAVE_GETOPT
35 # include <unistd.h>
36 extern char* optarg;
37 extern int optind;
38 #else
39 # include "getopt.h"
40 #endif
41 
42 #include "main.h"
43 #include "omniEvents.h"
44 #include "naming.h"
45 #include "omniEventsLog.h"
46 #include "EventChannelFactory.h"
47 #include "Orb.h"
48 #include "daemon.h"
49 #include "version.h"
50 
51 #if defined(HAVE_SIGNAL_H) && defined(HAVE_SIGSET)
52 # include <signal.h>
53 # define SIGSET(sig,func) ::sigset(sig,func)
54 #elif defined(HAVE_SIGNAL_H)
55 # include <signal.h>
56 # define SIGSET(sig,func) ::signal(sig,func)
57 #endif
58 
59 #ifdef HAVE_OMNIORB4
60 # include <omniORB4/internal/orbOptions.h>
61 #endif
62 
63 #include <cstdlib>
64 #include <stdio.h> // for sprintf
65 
66 int main(int argc, char** argv)
67 {
68  OmniEvents::Daemon daemon(argc,argv);
69 
70 #ifdef HAVE_OMNIORB4
71  try
72  {
73  // Duplicate argv & argc.
74  int originalArgc =argc;
75  char** originalArgv =new char*[originalArgc];
76  for(int i=0; i<originalArgc; ++i)
77  originalArgv[i]=strdup(argv[i]);
78 
79  // Remove ORB arguments from argc & argv.
80  try {
81  omni::orbOptions::singleton().extractInitOptions(argc,argv);
82  }
83  catch(...) {
84  argc=originalArgc;
85  argv=originalArgv;
86  }
87 #endif
88 
89  using namespace OmniEvents;
90 
91  //
92  // Process Options
93  const char* endPointNoListen =NULL;
94  int port =0;
95  const char* logDir =NULL;
96  const char* factoryName ="EventChannelFactory";
97  bool verbose =false;
98 
99  int c;
100  while ((c = getopt(argc,argv,"O:a:p:l:P:N:dft:vVh")) != EOF)
101  {
102  switch (c)
103  {
104  case 'O': break; // Helps protect us from -ORB arguments.
105 
106  // Initialisation options (only useful on first run)
107  case 'a': endPointNoListen=optarg;
108  break;
109 
110  case 'p': port=atoi(optarg);
111  if (port <= 0)
112  {
113  cerr<<"\nError: port must be a positive integer"<<endl;
114  usage(argc,argv);
115  }
116  break;
117 
118  // Other options
119  case 'l': logDir=optarg;
120  break;
121 
122  case 'P': daemon.pidfile(optarg);
123  break;
124 
125  case 'N': factoryName=optarg;
126  break;
127 
128  case 'd': cerr<<"Option '-d' is deprecated. Use '-f' instead."<<endl;
129  daemon.foreground(true);
130  break;
131 
132  case 'f': daemon.foreground(true);
133  break;
134 
135  // Informational options
136  case 't': daemon.tracefile(optarg);
137  break;
138 
139  case 'v': verbose=true;
140  break;
141 
142  case 'V': cout<<OmniEvents::version()<<endl;
143  ::exit(0);
144 
145  case 'h':
146  default : usage(argc,argv);
147  break;
148  }
149  }
150 
151  //
152  // Create database instance.
153  omniEventsLog logfile(logDir);
154  PersistNode* initialState =NULL;
155  if(logfile.fileExists(logfile.activeFilename()))
156  {
157  // Read library file.
158  initialState=logfile.parse();
159  // Check for incompatibilities between options and the file.
160  if(port && port!=initialState->child("ecf")->attrLong("port"))
161  {
162  cerr<<
163  "Error: Option '-p "<<port<<"' conflicts with value '"<<
164  initialState->child("ecf")->attrLong("port")<<"'\n stored in"
165  " database file '"<<logfile.activeFilename()<<"'.\n"
166  " Either delete the file to clear the database, or do not use the"
167  " '-p' option."<<endl;
168  exit(1);
169  }
170  if(endPointNoListen && string(endPointNoListen)!=
171  initialState->child("ecf")->attrString("endPointNoListen"))
172  {
173  cerr<<
174  "Error: Option '-a "<<endPointNoListen<<"' conflicts with value '"<<
175  initialState->child("ecf")->attrString("endPointNoListen")<<"'\n"
176  " stored in database file '"<<logfile.activeFilename()<<"'.\n"
177  " Either delete the file to clear the database, or do not use the"
178  " '-a' option."<<endl;
179  exit(1);
180  }
181  }
182  else if(logfile.fileExists(logfile.backupFilename()))
183  {
184  // Quit with an error.
185  cerr <<
186  "Error: backup file '" << logfile.backupFilename() << "' exists.\n"
187  " Rename it to '" << logfile.activeFilename() << "'\n"
188  " to recover the server's state, or delete it to create a new\n"
189  " database file." << endl;
190  exit(1);
191  }
192  else
193  {
194  // Create initial state without a library file.
195  initialState=logfile.bootstrap(port?port:11169,endPointNoListen);
196  }
197  port=initialState->child("ecf")->attrLong("port",port);
198  string endPoint2=initialState->child("ecf")->attrString("endPointNoListen");
199 
200  //
201  // Daemonise
202  daemon.daemonize();
203 
204  //
205  // Initialise orb & POAs.
206 #ifdef HAVE_OMNIORB4
207  char endPoint[64];
208  sprintf(endPoint,"giop:::%d",port);
209  if(endPoint2.empty())
210  {
211  const char* opts[][2] ={ {"endPoint",endPoint}, {0,0} };
212  Orb::inst()._orb=CORBA::ORB_init(originalArgc,originalArgv,"omniORB4",opts);
213  }
214  else
215  {
216  const char* opts[][2] ={
217  {"endPoint",endPoint},
218  {"endPointNoListen",endPoint2.c_str()},
219  {0,0} };
220  Orb::inst()._orb=CORBA::ORB_init(originalArgc,originalArgv,"omniORB4",opts);
221  }
222 #else
223  insertArgs(argc, argv, 1, 2);
224  argv[1] = strdup("-ORBpoa_iiop_port");
225  argv[2] = new char[32 + 1];
226  sprintf(argv[2], "%d", port);
227  Orb::inst()._orb=CORBA::ORB_init(argc,argv);
228 #endif
230  {
231  PortableServer::POAManager_var pman;
232  pman=Orb::inst()._RootPOA->the_POAManager();
233  pman->activate();
234  pman=Orb::inst()._omniINSPOA->the_POAManager();
235  pman->activate();
236  }
237 
238  //
239  // If omniEvents is restarting then the omniEventsLog object
240  // will take care of creating the factory and any subordinate
241  // event channels, proxies, etc under it.
242  logfile.incarnateFactory(initialState);
243  delete initialState; // Tidy up.
244  initialState=NULL;
245 
246  {
247  //
248  // Register factory with the Naming Service.
249  omniEvents::EventChannelFactory_var factory( logfile.factory()->_this() );
251  Orb::inst()._NameService.in(),
252  str2name(factoryName),
253  factory.in()
254  );
255 
256  //
257  // Print the factory IOR.
258  if(verbose)
259  {
260  DB(1,"Starting omniEvents on port "<<port)
261  if(!endPoint2.empty())
262  DB(1,"Alternate endPoint "<<endPoint2.c_str())
263  CORBA::String_var iorstr =
264  Orb::inst()._orb->object_to_string(factory.in());
265  DB(1,iorstr.in())
266  }
267  } // factory reference is released.
268 
269 #ifdef HAVE_SIGNAL_H
270  SIGSET(SIGINT , ::OmniEvents_Orb_shutdown);
271  SIGSET(SIGTERM, ::OmniEvents_Orb_shutdown);
272 # ifdef SIGUSR1
273  SIGSET(SIGUSR1, ::OmniEvents_Orb_bumpTraceLevel);
274 # endif
275 # ifdef SIGPIPE
276  SIGSET(SIGPIPE, SIG_IGN); // Ignore broken pipes
277 # endif
278 #endif
279 
280  daemon.runningOk();
281 
282  //
283  // Start the background tasks.
284  logfile.runWorker(); // Logfile's worker thread.
285  Orb::inst().run(); // Use the main thread to collect orphaned responses.
286 
287  DB(1,"Shutdown requested.")
288  Orb::inst()._orb->shutdown(1); // Synchronous shutdown
289  Orb::inst()._orb->destroy(); // clean up
290 
291  return 0; // Delete any pidfile & exit.
292 
293 #ifdef HAVE_OMNIORB4
294  }
295  catch (CORBA::SystemException& ex) {
296  DB(0,"System exception: "<<ex._name()<<" ("<<NP_MINORSTRING(ex)<<")")
297  }
298  catch (CORBA::Exception& ex) {
299  DB(0,"CORBA exception: "<<ex._name())
300  }
301  return 1;
302 #endif
303 } // end main()
304 
305 
306 //
307 // Signal handlers.
308 //
309 
310 extern "C"
311 {
312  void OmniEvents_Orb_shutdown(int signum)
313  {
315  }
316 
318  {
319  omniORB::traceLevel=(omniORB::traceLevel+5)%45;
320  DB(0,"TRACE LEVEL BUMPED TO "<<omniORB::traceLevel<<" BY SIGNAL "<<signum)
321  }
322 }
int optind
Definition: getopt.cc:82
char * optarg
Definition: getopt.cc:83
int getopt(int argc, char *argv[], const char *optionS)
Definition: getopt.cc:88
int main(int argc, char **argv)
The main process entry point.
Definition: main.cc:66
void OmniEvents_Orb_shutdown(int signum)
Signal handler, sets Orb::_shutdownRequested.
Definition: main.cc:312
void OmniEvents_Orb_bumpTraceLevel(int signum)
Signal handler, each call to this method 'bumps' up the trace level by 5, modulo 45.
Definition: main.cc:317
int bindName2Object(CosNaming::NamingContext_ptr namingContext, const CosNaming::Name &name, CORBA::Object_ptr obj)
Binds CosNaming::Name to object in the naming service.
Definition: naming.cc:149
CosNaming::Name str2name(const char *namestr)
Converts stringified name to naming service name.
Definition: naming.cc:117
#define DB(l, x)
Definition: Orb.h:49
#define NP_MINORSTRING(systemException)
Definition: Orb.h:52
void insertArgs(int &argc, char **&argv, int idx, int nargs)
Utility function, used to manipulate argv when using omniORB3.
Definition: omniEvents.cc:97
DaemonImpl daemon
Singleton - only at file scope.
Definition: daemon_unix.cc:94
const char * version()
Returns the constant version ID and copyright string.
Definition: version.cc:32
void usage(int argc, char **argv)
Definition: omniEvents.cc:49
Interface class that contains various methods for running omniEvents as a background task.
Definition: daemon.h:33
void runningOk()
Called to signal that all startup operations have completed OK.
Definition: daemon_unix.cc:215
void foreground(bool val)
Set _foreground.
Definition: daemon_unix.cc:137
void tracefile(const char *val)
Set _tracefile.
Definition: daemon_unix.cc:131
void pidfile(const char *val)
Set _pidfile.
Definition: daemon_unix.cc:143
void daemonize()
Puts the current process into the background.
Definition: daemon_unix.cc:158
Singleton class that owns the ORB and various initial references.
Definition: Orb.h:70
PortableServer::POA_var _RootPOA
Definition: Orb.h:89
CORBA::ORB_var _orb
Definition: Orb.h:88
void shutdown(int)
Sets _shutdownRequested.
Definition: Orb.h:126
static Orb & inst()
Definition: Orb.h:81
void resolveInitialReferences()
_orb must already have been initialized before this method is called.
Definition: Orb.cc:55
void run()
Parks the main thread, but also picks up (and ignores) responses from orphan requests.
Definition: Orb.cc:124
PortableServer::POA_var _omniINSPOA
Definition: Orb.h:90
string attrString(const string &key, const string &fallback="") const
Definition: PersistNode.cc:155
long attrLong(const string &key, long fallback=0) const
Definition: PersistNode.cc:163
PersistNode * child(const string &key) const
Definition: PersistNode.cc:171