Merge pull request #2216 from jwillemsen/jwi-cxxversionchecks
[ACE_TAO.git] / ACE / examples / C++NPv1 / Process_Per_Connection_Logging_Server.cpp
blob6dc758236820f822cb9cd32ee1f927268df1e84b
1 /*
2 ** Copyright 2001 Addison Wesley. All Rights Reserved.
3 */
5 #include "ace/Log_Msg.h"
6 #include "ace/Process_Manager.h"
7 #include "ace/Signal.h"
8 #include "ace/OS_NS_string.h"
9 #include "ace/os_include/os_fcntl.h"
11 #include "Process_Per_Connection_Logging_Server.h"
12 #include "Logging_Handler.h"
14 #include <errno.h>
16 namespace {
17 extern "C" void sigterm_handler (int /* signum */) { /* No-op. */ }
21 Logging_Process::Logging_Process (const char *prog_name,
22 const ACE_SOCK_Stream &logging_peer)
23 : logging_peer_ (logging_peer.get_handle ())
25 ACE_OS::strcpy (prog_name_, prog_name);
28 // Set up the process options here. If the decision to do a fork
29 // a no exec on POSIX needs to be changed, this is the only place
30 // that needs to change (omit the creation_flags() call).
31 // We request that the logging client's socket handle be passed
32 // to the child process. The internals of ACE_Process insure that
33 // it gets put on the command line if starting a new program image,
34 // and that if it needed to be duplicated to accomplish that (such
35 // as on Win32) it will get properly closed.
36 // The process_name () call sets the program to run and is also used
37 // for the fork() call on POSIX.
38 // avoid_zombies has a real affect only on POSIX; it's harmless on Win32.
39 // Setting the NO_EXEC creation flag is what prevents the exec() on
40 // POSIX. It has no affect on Win32.
41 int
42 Logging_Process::prepare (ACE_Process_Options &options)
44 if (options.pass_handle (logging_peer_.get_handle ()) == -1)
45 ACE_ERROR_RETURN ((LM_ERROR, "%p\n", "pass_handle"), -1);
46 options.command_line ("%s", prog_name_);
47 options.avoid_zombies (1);
48 options.creation_flags (ACE_Process_Options::NO_EXEC);
49 return 0;
52 // Just delete the process object. If any handles needed to be
53 // duplicated to be passed to the child, they'll get closed now
54 // by the ACE_Process destructor.
55 void
56 Logging_Process::unmanage ()
58 delete this;
62 int
63 Process_Per_Connection_Logging_Server::handle_connections ()
65 ACE_SOCK_Stream logging_peer;
67 // Block until a client connects.
68 if (acceptor ().accept (logging_peer) == -1)
69 return -1;
71 Logging_Process *logger =
72 new Logging_Process (prog_name_, logging_peer);
73 ACE_Process_Options options;
74 pid_t pid;
75 pid = ACE_Process_Manager::instance ()->spawn (logger,
76 options);
77 // If we came back with pid 0 from the spawn(), this is a
78 // POSIX fork system - we are in the child process. Handle the
79 // logging records, then exit.
80 if (pid == 0) {
81 acceptor().close ();
82 handle_data (&logging_peer);
83 delete logger;
84 ACE_OS::exit (0);
86 logging_peer.close ();
87 if (pid == -1)
88 ACE_ERROR_RETURN ((LM_ERROR, "%p\n", "spawn()"), -1);
90 // See if there are any child processes that have
91 // exited - reap their status and clean up handles held
92 // open while the child executed.
93 ACE_Process_Manager::instance ()->wait (0,
94 ACE_Time_Value::zero);
95 return 0;
98 int
99 Process_Per_Connection_Logging_Server::handle_data (ACE_SOCK_Stream *client)
101 // Disable non-blocking mode.
102 client->disable (ACE_NONBLOCK);
103 ACE_FILE_IO log_file;
104 make_log_file (log_file, client);
105 Logging_Handler logging_handler (log_file, *client);
107 while (logging_handler.log_record () != -1)
108 continue;
110 log_file.close ();
111 return 0;
116 Process_Per_Connection_Logging_Server::run (int argc, char *argv[])
118 ACE_OS::strncpy (prog_name_, argv[0], MAXPATHLEN);
119 prog_name_[MAXPATHLEN] = '\0'; // Ensure NUL-termination.
120 // If there are 2 command line arguments after prog_name_, this
121 // is a spawned worker process. Else run as the master.
122 if (argc == 3)
123 return run_worker (argc, argv); // Only on Win32.
124 else
125 return run_master (argc, argv);
129 Process_Per_Connection_Logging_Server::run_master (int argc, char *argv[])
131 u_short logger_port = 0;
132 if (argc == 2)
133 logger_port = ACE_OS::atoi (argv[1]);
134 if (this->open (logger_port) == -1)
135 return -1;
137 for (;;)
138 if (handle_connections () == -1)
139 return -1;
141 ACE_NOTREACHED (return 0;)
145 Process_Per_Connection_Logging_Server::run_worker (int, char *argv[])
147 // The handle value is passed as a hex pointer value on Windows and a
148 // decimal number everywhere else. See ace/Process.cpp for info.
149 #if defined (ACE_WIN32)
150 intptr_t client_handle_i = 0;
151 # if defined (ACE_WIN64)
152 const char *fmt = "%I64x";
153 # else
154 const char *fmt = "%x";
155 # endif /* ACE_WIN64 */
156 # if defined (ACE_HAS_TR24731_2005_CRT)
157 if (::sscanf_s (argv[2], fmt, &client_handle_i) == 0)
158 return -1;
159 # else
160 if (::sscanf (argv[2], fmt, &client_handle_i) == 0)
161 return -1;
162 # endif /* ACE_HAS_TR24731_2005_CRT */
163 ACE_HANDLE client_handle =
164 reinterpret_cast<ACE_HANDLE> (client_handle_i);
165 #else
166 ACE_HANDLE client_handle = static_cast<ACE_HANDLE> (ACE_OS::atoi (argv[2]));
167 #endif /* ACE_WIN32 */
168 ACE_SOCK_Stream client (client_handle);
170 handle_data (&client);
171 client.close ();
172 return 0;
176 int ACE_TMAIN (int argc, ACE_TCHAR *argv[])
178 // Register to receive the <SIGTERM> signal.
179 ACE_Sig_Action sa ((ACE_SignalHandler)sigterm_handler,
180 SIGTERM);
182 Process_Per_Connection_Logging_Server server;
184 if (server.run (argc, argv) == -1 && errno != EINTR)
185 ACE_ERROR_RETURN ((LM_ERROR, "%p\n", "server.run()"), 1);
187 // Barrier synchronization.
188 return ACE_Process_Manager::instance ()->wait ();