Merge pull request #2309 from mitza-oci/warnings
[ACE_TAO.git] / ACE / apps / JAWS / server / HTTP_Server.cpp
blob4fdd569027032126f073f9285f8a109ea99a6c45
1 #ifndef ACE_BUILD_SVC_DLL
2 #define ACE_BUILD_SVC_DLL
3 #endif /* ACE_BUILD_SVC_DLL */
5 #include "ace/OS_NS_string.h"
6 #include "ace/Get_Opt.h"
7 #include "ace/Asynch_Acceptor.h"
8 #include "ace/LOCK_SOCK_Acceptor.h"
9 #include "ace/Proactor.h"
10 #include "ace/Signal.h"
12 #include "JAWS_IO.h"
13 #include "HTTP_Server.h"
14 #include <memory>
16 // class is overkill
17 class JAWS
19 public:
20 enum
22 JAWS_POOL = 0,
23 JAWS_PER_REQUEST = 1
26 enum
28 JAWS_SYNCH = 0,
29 JAWS_ASYNCH = 2
33 void
34 HTTP_Server::parse_args (int argc, ACE_TCHAR *argv[])
36 int c;
37 int thr_strategy = 0;
38 int io_strategy = 0;
39 const ACE_TCHAR *prog = argc > 0 ? argv[0] : ACE_TEXT ("HTTP_Server");
41 // Set some defaults
42 this->port_ = 0;
43 this->threads_ = 0;
44 this->backlog_ = 0;
45 this->throttle_ = 0;
46 this->caching_ = true;
48 ACE_Get_Opt get_opt (argc, argv, ACE_TEXT ("p:n:t:i:b:c:"));
50 while ((c = get_opt ()) != -1)
51 switch (c)
53 case 'p':
54 this->port_ = ACE_OS::atoi (get_opt.opt_arg ());
55 break;
56 case 'n':
57 this->threads_ = ACE_OS::atoi (get_opt.opt_arg ());
58 break;
59 case 't':
60 // POOL -> thread pool
61 // PER_REQUEST -> thread per request
62 // THROTTLE -> thread per request with throttling
63 if (ACE_OS::strcmp (get_opt.opt_arg (), ACE_TEXT ("POOL")) == 0)
64 thr_strategy = JAWS::JAWS_POOL;
65 else if (ACE_OS::strcmp (get_opt.opt_arg (), ACE_TEXT ("PER_REQUEST")) == 0)
67 thr_strategy = JAWS::JAWS_PER_REQUEST;
68 this->throttle_ = 0;
70 else if (ACE_OS::strcmp (get_opt.opt_arg (), ACE_TEXT ("THROTTLE")) == 0)
72 thr_strategy = JAWS::JAWS_PER_REQUEST;
73 this->throttle_ = 1;
75 break;
76 case 'f':
77 if (ACE_OS::strcmp (get_opt.opt_arg (), ACE_TEXT ("THR_BOUND")) == 0)
79 // What happened here?
81 else if (ACE_OS::strcmp (get_opt.opt_arg (), ACE_TEXT ("THR_DAEMON")) == 0)
84 else if (ACE_OS::strcmp (get_opt.opt_arg (), ACE_TEXT ("THR_DETACHED")) == 0)
87 break;
88 case 'i':
89 // SYNCH -> synchronous I/O
90 // ASYNCH -> asynchronous I/O
91 if (ACE_OS::strcmp (get_opt.opt_arg (), ACE_TEXT ("SYNCH")) == 0)
92 io_strategy = JAWS::JAWS_SYNCH;
93 else if (ACE_OS::strcmp (get_opt.opt_arg (), ACE_TEXT ("ASYNCH")) == 0)
94 io_strategy = JAWS::JAWS_ASYNCH;
95 break;
96 case 'b':
97 this->backlog_ = ACE_OS::atoi (get_opt.opt_arg ());
98 break;
99 case 'c':
100 if (ACE_OS::strcmp (get_opt.opt_arg (), ACE_TEXT ("NO_CACHE")) == 0)
101 this->caching_ = false;
102 else
103 this->caching_ = true;
104 break;
105 default:
106 break;
109 // No magic numbers.
110 if (this->port_ <= 0)
111 this->port_ = 5432;
112 if (this->threads_ <= 0)
113 this->threads_ = 5;
114 // Don't use number of threads as default
115 if (this->backlog_ <= 0)
116 this->backlog_ = this->threads_;
118 this->strategy_ = thr_strategy | io_strategy;
120 ACE_UNUSED_ARG (prog);
121 ACE_DEBUG ((LM_DEBUG,
122 ACE_TEXT ("in HTTP_Server::init, %s port = %d, ")
123 ACE_TEXT ("number of threads = %d\n"),
124 prog, this->port_, this->threads_));
128 HTTP_Server::init (int argc, ACE_TCHAR *argv[])
129 // Document this function
131 // Ignore signals generated when a connection is broken unexpectedly.
132 ACE_Sig_Action sig ((ACE_SignalHandler) SIG_IGN, SIGPIPE);
133 ACE_UNUSED_ARG (sig);
135 // Parse arguments which sets the initial state.
136 this->parse_args (argc, argv);
138 //If the IO strategy is synchronous (SYNCH case), then choose a handler
139 //factory based on the desired caching scheme
140 HTTP_Handler_Factory *f = 0;
142 if (this->strategy_ != (JAWS::JAWS_POOL | JAWS::JAWS_ASYNCH))
144 if (this->caching_)
146 ACE_NEW_RETURN (f, Synch_HTTP_Handler_Factory (), -1);
148 else
150 ACE_NEW_RETURN (f, No_Cache_Synch_HTTP_Handler_Factory (), -1);
154 //NOTE: At this point f better not be a NULL pointer,
155 //so please do not change the ACE_NEW_RETURN macros unless
156 //you know what you are doing
157 std::unique_ptr<HTTP_Handler_Factory> factory (f);
159 // Choose what concurrency strategy to run.
160 switch (this->strategy_)
162 case (JAWS::JAWS_POOL | JAWS::JAWS_ASYNCH) :
163 return this->asynch_thread_pool ();
165 case (JAWS::JAWS_PER_REQUEST | JAWS::JAWS_SYNCH) :
166 return this->thread_per_request (*factory.get ());
168 case (JAWS::JAWS_POOL | JAWS::JAWS_SYNCH) :
169 default:
170 return this->synch_thread_pool (*factory.get ());
173 ACE_NOTREACHED (return 0);
177 HTTP_Server::fini ()
179 this->tm_.close ();
180 return 0;
185 HTTP_Server::synch_thread_pool (HTTP_Handler_Factory &factory)
187 // Main thread opens the acceptor
188 if (this->acceptor_.open (ACE_INET_Addr (this->port_), 1,
189 PF_INET, this->backlog_) == -1)
190 ACE_ERROR_RETURN ((LM_ERROR, ACE_TEXT ("%p\n"),
191 ACE_TEXT ("HTTP_Acceptor::open")), -1);
193 // Create a pool of threads to handle incoming connections.
194 Synch_Thread_Pool_Task t (this->acceptor_, this->tm_, this->threads_, factory);
196 this->tm_.wait ();
197 return 0;
200 Synch_Thread_Pool_Task::Synch_Thread_Pool_Task (HTTP_Acceptor &acceptor,
201 ACE_Thread_Manager &tm,
202 int threads,
203 HTTP_Handler_Factory &factory)
204 : ACE_Task<ACE_NULL_SYNCH> (&tm),
205 acceptor_ (acceptor),
206 factory_ (factory)
208 if (this->activate (THR_DETACHED | THR_NEW_LWP, threads) == -1)
209 ACE_ERROR ((LM_ERROR, ACE_TEXT ("%p\n"),
210 ACE_TEXT ("Synch_Thread_Pool_Task::open")));
214 Synch_Thread_Pool_Task::svc ()
216 // Creates a factory of HTTP_Handlers binding to synchronous I/O strategy
217 //Synch_HTTP_Handler_Factory factory;
219 for (;;)
221 ACE_SOCK_Stream stream;
223 // Lock in this accept. When it returns, we have a connection.
224 if (this->acceptor_.accept (stream) == -1)
225 ACE_ERROR_RETURN ((LM_ERROR, ACE_TEXT("%p\n"),
226 ACE_TEXT ("HTTP_Acceptor::accept")), -1);
228 ACE_Message_Block *mb = 0;
229 ACE_NEW_RETURN (mb,
230 ACE_Message_Block (HTTP_Handler::MAX_REQUEST_SIZE + 1),
231 -1);
233 // Create an HTTP Handler to handle this request
234 HTTP_Handler *handler = this->factory_.create_http_handler ();
235 handler->open (stream.get_handle (), *mb);
236 // Handler is destroyed when the I/O puts the Handler into the
237 // done state.
239 mb->release ();
240 ACE_DEBUG ((LM_DEBUG,
241 ACE_TEXT (" (%t) in Synch_Thread_Pool_Task::svc, recycling\n")));
244 ACE_NOTREACHED(return 0);
248 HTTP_Server::thread_per_request (HTTP_Handler_Factory &factory)
250 int grp_id = -1;
252 // thread per request
253 // Main thread opens the acceptor
254 if (this->acceptor_.open (ACE_INET_Addr (this->port_), 1,
255 PF_INET, this->backlog_) == -1)
256 ACE_ERROR_RETURN ((LM_ERROR, ACE_TEXT ("%p\n"),
257 ACE_TEXT ("HTTP_Acceptor::open")), -1);
259 ACE_SOCK_Stream stream;
261 // When we are throttling, this is the amount of time to wait before
262 // checking for runnability again.
263 const ACE_Time_Value wait_time (0, 10);
265 for (;;)
267 if (this->acceptor_.accept (stream) == -1)
268 ACE_ERROR_RETURN ((LM_ERROR, ACE_TEXT ("%p\n"),
269 ACE_TEXT ("HTTP_Acceptor::accept")), -1);
271 Thread_Per_Request_Task *t;
272 // Pass grp_id as a constructor param instead of into open.
273 ACE_NEW_RETURN (t, Thread_Per_Request_Task (stream.get_handle (),
274 this->tm_,
275 grp_id,
276 factory),
277 -1);
280 if (t->open () != 0)
281 ACE_ERROR_RETURN ((LM_ERROR, ACE_TEXT ("%p\n"),
282 ACE_TEXT ("Thread_Per_Request_Task::open")),
283 -1);
285 // Throttling is not allowing too many threads to run away.
286 // Should really use some sort of condition variable here.
287 if (!this->throttle_)
288 continue;
290 // This works because each task has only one thread.
291 while (this->tm_.num_tasks_in_group (grp_id) > this->threads_)
292 this->tm_.wait (&wait_time);
295 ACE_NOTREACHED(return 0);
298 Thread_Per_Request_Task::Thread_Per_Request_Task (ACE_HANDLE handle,
299 ACE_Thread_Manager &tm,
300 int &grp_id,
301 HTTP_Handler_Factory &factory)
302 : ACE_Task<ACE_NULL_SYNCH> (&tm),
303 handle_ (handle),
304 grp_id_ (grp_id),
305 factory_ (factory)
310 // HEY! Add a method to the thread_manager to return total number of
311 // threads managed in all the tasks.
314 Thread_Per_Request_Task::open (void *)
316 int status = -1;
318 if (this->grp_id_ == -1)
319 status = this->grp_id_ = this->activate (THR_DETACHED | THR_NEW_LWP);
320 else
321 status = this->activate (THR_DETACHED | THR_NEW_LWP,
322 1, 0, -1, this->grp_id_, 0);
324 if (status == -1)
325 ACE_ERROR_RETURN ((LM_ERROR, ACE_TEXT ("%p\n"),
326 ACE_TEXT ("Thread_Per_Request_Task::open")),
327 -1);
328 return 0;
332 Thread_Per_Request_Task::svc ()
334 ACE_Message_Block *mb = 0;
335 ACE_NEW_RETURN (mb, ACE_Message_Block (HTTP_Handler::MAX_REQUEST_SIZE + 1),
336 -1);
337 //Synch_HTTP_Handler_Factory factory;
338 HTTP_Handler *handler = this->factory_.create_http_handler ();
339 handler->open (this->handle_, *mb);
340 mb->release ();
341 return 0;
345 Thread_Per_Request_Task::close (u_long)
347 ACE_DEBUG ((LM_DEBUG,
348 ACE_TEXT (" (%t) Thread_Per_Request_Task::svc, dying\n")));
349 delete this;
350 return 0;
353 // Understanding the code below requires understanding of the
354 // WindowsNT asynchronous completion notification mechanism and the
355 // Proactor Pattern.
357 // (1) The application submits an asynchronous I/O request to the
358 // operating system and a special handle with it (Asynchronous
359 // Completion Token).
360 // (2) The operating system commits to performing the I/O request,
361 // while application does its own thing.
362 // (3) Operating system finishes the I/O request and places ACT onto
363 // the I/O Completion Port, which is a queue of finished
364 // asynchronous requests.
365 // (4) The application eventually checks to see if the I/O request
366 // is done by checking the I/O Completion Port, and retrieves the
367 // ACT.
370 HTTP_Server::asynch_thread_pool ()
372 // This only works on Win32
373 #if defined (ACE_HAS_WIN32_OVERLAPPED_IO)
374 // Create the appropriate acceptor for this concurrency strategy and
375 // an appropriate handler for this I/O strategy
376 ACE_Asynch_Acceptor<Asynch_HTTP_Handler_Factory> acceptor;
378 // Tell the acceptor to listen on this->port_, which makes an
379 // asynchronous I/O request to the OS.
380 if (acceptor.open (ACE_INET_Addr (this->port_),
381 HTTP_Handler::MAX_REQUEST_SIZE + 1) == -1)
382 ACE_ERROR_RETURN ((LM_ERROR, ACE_TEXT ("%p\n"),
383 ACE_TEXT ("ACE_Asynch_Acceptor::open")), -1);
385 // Create the thread pool.
386 // Register threads with the proactor and thread manager.
387 Asynch_Thread_Pool_Task t (*ACE_Proactor::instance (),
388 this->tm_);
390 // The proactor threads are waiting on the I/O Completion Port.
392 // Wait for the threads to finish.
393 return this->tm_.wait ();
394 #endif /* ACE_HAS_WIN32_OVERLAPPED_IO */
395 return -1;
398 // This only works on Win32
399 #if defined (ACE_HAS_WIN32_OVERLAPPED_IO)
401 Asynch_Thread_Pool_Task::Asynch_Thread_Pool_Task (ACE_Proactor &proactor,
402 ACE_Thread_Manager &tm)
403 : ACE_Task<ACE_NULL_SYNCH> (&tm),
404 proactor_ (proactor)
406 if (this->activate () == -1)
407 ACE_ERROR ((LM_ERROR, ACE_TEXT ("%p\n"),
408 ACE_TEXT ("Asynch_Thread_Pool_Task::open")));
412 Asynch_Thread_Pool_Task::svc ()
414 for (;;)
415 if (this->proactor_.handle_events () == -1)
416 ACE_ERROR_RETURN ((LM_ERROR, ACE_TEXT ("%p\n"),
417 ACE_TEXT ("ACE_Proactor::handle_events")),
418 -1);
420 return 0;
423 #endif /* ACE_HAS_WIN32_OVERLAPPED_IO */
425 // Define the factory function.
426 ACE_SVC_FACTORY_DEFINE (HTTP_Server)
428 // Define the object that describes the service.
429 ACE_STATIC_SVC_DEFINE (HTTP_Server, ACE_TEXT ("HTTP_Server"), ACE_SVC_OBJ_T,
430 &ACE_SVC_NAME (HTTP_Server),
431 ACE_Service_Type::DELETE_THIS
432 | ACE_Service_Type::DELETE_OBJ, 0)