\r
if (!shar_checkonly) {\r
// Run the listener.\r
- if (!conf.getServiceProvider()->getListenerService()->run(unlink_socket, &shibd_shutdown)) {\r
- fprintf(stderr, "listener failed to enter listen loop\n");\r
+ ListenerService* listener = conf.getServiceProvider()->getListenerService();\r
+ if (!listener->init(unlink_socket)) {\r
+ fprintf(stderr, "listener failed to initialize\n");\r
return -3;\r
}\r
+ else if (!listener->run(&shibd_shutdown)) {\r
+ listener->term();\r
+ fprintf(stderr, "listener failed to begin service\n");\r
+ return -3;\r
+ }\r
+ listener->term();\r
}\r
\r
conf.term();\r
shibd_running = true;\r
}\r
\r
+static void child_handler(int arg)\r
+{\r
+ // Terminate the parent's wait/sleep if the newly born daemon dies early.\r
+}\r
+\r
static int setup_signals(void)\r
{\r
struct sigaction sa;\r
if (sigaction(SIGUSR1, &sa, NULL) < 0) {\r
return -1;\r
}\r
+\r
+ memset(&sa, 0, sizeof (sa));\r
+ sa.sa_handler = child_handler;\r
+\r
+ if (sigaction(SIGCHLD, &sa, NULL) < 0) {\r
+ return -1;\r
+ }\r
}\r
\r
return 0;\r
break;\r
case 't':\r
shar_checkonly=true;\r
+ daemonize=false;\r
break;\r
case 'v':\r
shar_version=true;\r
if (daemonize) {\r
// We must fork() early, while we're single threaded.\r
// StorageService cleanup thread is about to start.\r
- if (!shar_checkonly) {\r
- switch (fork()) {\r
- case 0:\r
- break;\r
- case -1:\r
- perror("forking");\r
+ pid_t pid = fork();\r
+ switch (pid) {\r
+ case 0:\r
+ break;\r
+ case -1:\r
+ perror("forking");\r
+ exit(EXIT_FAILURE);\r
+ default:\r
+ sleep(daemon_wait);\r
+ if (shibd_running) {\r
+ if (pidfile) {\r
+ FILE* pidf = fopen(pidfile, "w");\r
+ if (pidf) {\r
+ fprintf(pidf, "%d\n", pid);\r
+ fclose(pidf);\r
+ }\r
+ else {\r
+ perror(pidfile);\r
+ }\r
+ }\r
+ exit(EXIT_SUCCESS);\r
+ }\r
+ else {\r
exit(EXIT_FAILURE);\r
- default:\r
- sleep(daemon_wait);\r
- exit(shibd_running ? EXIT_SUCCESS : EXIT_FAILURE);\r
- }\r
+ }\r
}\r
}\r
\r
}\r
}\r
\r
- // Write the pid file\r
- if (pidfile) {\r
- FILE* pidf = fopen(pidfile, "w");\r
- if (pidf) {\r
- fprintf(pidf, "%d\n", getpid());\r
- fclose(pidf);\r
- } else {\r
- perror(pidfile); // keep running though\r
- }\r
- }\r
-\r
if (daemonize) {\r
freopen("/dev/null", "r", stdin);\r
freopen("/dev/null", "w", stdout);\r
freopen("/dev/null", "w", stderr);\r
- if (!conf.getServiceProvider()->getListenerService()->setSignal(SIGUSR1)) {\r
- fprintf(stderr, "listener failed to accept signaling hook\n");\r
- return -3;\r
- }\r
}\r
\r
- // Run the listener\r
- if (!conf.getServiceProvider()->getListenerService()->run(unlink_socket, &shibd_shutdown)) {\r
- fprintf(stderr, "listener failed to enter listen loop\n");\r
+ // Init the listener.\r
+ ListenerService* listener = conf.getServiceProvider()->getListenerService();\r
+ if (!listener->init(unlink_socket)) {\r
+ fprintf(stderr, "listener failed to initialize\n");\r
+ return -3;\r
+ }\r
+\r
+ // Signal our parent.\r
+ pid_t ppid = getppid();\r
+ kill(ppid, SIGUSR1);\r
+\r
+ // Run the listener.\r
+ if (!listener->run(&shibd_shutdown)) {\r
+ listener->term();\r
+ fprintf(stderr, "listener failed to begin service\n");\r
return -3;\r
}\r
+ listener->term();\r
}\r
\r
conf.term();\r
*/
virtual Remoted* lookup(const char* address) const;
-#ifndef WIN32
/**
- * Installs a signal that the service should raise to its parent process
- * before entering a running state.
+ * OutOfProcess servers can implement server-side initialization that should occur
+ * before daemonization.
*
- * @param s the signal to raise
- * @return true iff the signal was successfully installed
+ * <p>The parameter applies to implementations that can detect and remove
+ * the results of ungraceful shutdowns of previous executions and continue
+ * successfully. File-based sockets are the most common example.
+ *
+ * @param force true iff remnant network state should be forcibly cleared
+ * @return true iff the service initialization was successful
*/
- virtual bool setSignal(int s) {
- return false;
+ virtual bool init(bool force) {
+ return true;
}
-#endif
/**
- * @deprecated
* OutOfProcess servers can implement server-side transport handling by
* calling the run method and supplying a flag to monitor for shutdown.
*
virtual bool run(bool* shutdown)=0;
/**
- * OutOfProcess servers can implement server-side transport handling by
- * calling the run method and supplying a flag to monitor for shutdown.
- *
- * <p>The first parameter applies to implementations that can detect and remove
- * the results of ungraceful shutdowns of previous executions and continue
- * successfully. File-based sockets are the most common example.
- *
- * @param force true iff remnant network state should be forcibly cleared
- * @param shutdown pointer to flag that caller will set when shutdown is required
- * @return true iff the service execution was successful
+ * OutOfProcess servers can implement server-side termination/cleanup.
*/
- virtual bool run(bool force, bool* shutdown);
+ virtual void term() {
+ }
private:
std::map<std::string,Remoted*> m_listenerMap;
dest->receive(in, out);
}
-
-bool ListenerService::run(bool force, bool* shutdown)
-{
- return run(shutdown);
-}
delete m_child_lock;
}
-bool SocketListener::run(bool force, bool* shutdown)
+bool SocketListener::init(bool force)
{
#ifdef _DEBUG
- NDC ndc("run");
+ NDC ndc("init");
#endif
log->info("listener service starting");
}
sp->unlock();
- // Save flag to monitor for shutdown request.
- m_shutdown=shutdown;
- unsigned long count = 0;
-
if (!create(m_socket)) {
log->crit("failed to create socket");
return false;
return false;
}
-#ifndef WIN32
- if (m_signal) {
- // Notify our parent that we're entering the select loop.
- pid_t ppid = getppid();
- kill(ppid, SIGUSR1);
- log->info("notified parent (%d) upon entering select loop", ppid);
- }
+ return true;
+}
+
+bool SocketListener::run(bool* shutdown)
+{
+#ifdef _DEBUG
+ NDC ndc("run");
#endif
+ // Save flag to monitor for shutdown request.
+ m_shutdown=shutdown;
+ unsigned long count = 0;
while (!*m_shutdown) {
fd_set readfds;
if (errno == EINTR) continue;
log_error();
log->error("select() on main listener socket failed");
- return false;
+ *m_shutdown = true;
+ break;
case 0:
continue;
m_child_wait->wait(m_child_lock);
m_child_lock->unlock();
+ return true;
+}
+
+void SocketListener::term()
+{
this->close(m_socket);
m_socket=(ShibSocket)0;
- return true;
}
DDF SocketListener::send(const DDF& in)
DDF send(const DDF& in);
-#ifndef WIN32
- bool setSignal(int s) {
- m_signal = s;
- return true;
- }
-#endif
-
- bool run(bool* shutdown) {
- return run(true, shutdown);
- }
- bool run(bool force, bool* shutdown);
+ bool init(bool force);
+ bool run(bool* shutdown);
+ void term();
// Implemented by socket-specific subclasses.
#ifdef WIN32
private:
mutable SocketPool* m_socketpool;
-#ifndef WIN32
- int m_signal;
-#endif
bool* m_shutdown;
// Manage child threads