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"
13 #include "HTTP_Server.h"
34 HTTP_Server::parse_args (int argc
, ACE_TCHAR
*argv
[])
39 const ACE_TCHAR
*prog
= argc
> 0 ? argv
[0] : ACE_TEXT ("HTTP_Server");
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)
54 this->port_
= ACE_OS::atoi (get_opt
.opt_arg ());
57 this->threads_
= ACE_OS::atoi (get_opt
.opt_arg ());
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
;
70 else if (ACE_OS::strcmp (get_opt
.opt_arg (), ACE_TEXT ("THROTTLE")) == 0)
72 thr_strategy
= JAWS::JAWS_PER_REQUEST
;
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)
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
;
97 this->backlog_
= ACE_OS::atoi (get_opt
.opt_arg ());
100 if (ACE_OS::strcmp (get_opt
.opt_arg (), ACE_TEXT ("NO_CACHE")) == 0)
101 this->caching_
= false;
103 this->caching_
= true;
110 if (this->port_
<= 0)
112 if (this->threads_
<= 0)
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
))
146 ACE_NEW_RETURN (f
, Synch_HTTP_Handler_Factory (), -1);
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
) :
170 return this->synch_thread_pool (*factory
.get ());
173 ACE_NOTREACHED (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
);
200 Synch_Thread_Pool_Task::Synch_Thread_Pool_Task (HTTP_Acceptor
&acceptor
,
201 ACE_Thread_Manager
&tm
,
203 HTTP_Handler_Factory
&factory
)
204 : ACE_Task
<ACE_NULL_SYNCH
> (&tm
),
205 acceptor_ (acceptor
),
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;
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;
230 ACE_Message_Block (HTTP_Handler::MAX_REQUEST_SIZE
+ 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
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
)
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);
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 (),
281 ACE_ERROR_RETURN ((LM_ERROR
, ACE_TEXT ("%p\n"),
282 ACE_TEXT ("Thread_Per_Request_Task::open")),
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_
)
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
,
301 HTTP_Handler_Factory
&factory
)
302 : ACE_Task
<ACE_NULL_SYNCH
> (&tm
),
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 *)
318 if (this->grp_id_
== -1)
319 status
= this->grp_id_
= this->activate (THR_DETACHED
| THR_NEW_LWP
);
321 status
= this->activate (THR_DETACHED
| THR_NEW_LWP
,
322 1, 0, -1, this->grp_id_
, 0);
325 ACE_ERROR_RETURN ((LM_ERROR
, ACE_TEXT ("%p\n"),
326 ACE_TEXT ("Thread_Per_Request_Task::open")),
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),
337 //Synch_HTTP_Handler_Factory factory;
338 HTTP_Handler
*handler
= this->factory_
.create_http_handler ();
339 handler
->open (this->handle_
, *mb
);
345 Thread_Per_Request_Task::close (u_long
)
347 ACE_DEBUG ((LM_DEBUG
,
348 ACE_TEXT (" (%t) Thread_Per_Request_Task::svc, dying\n")));
353 // Understanding the code below requires understanding of the
354 // WindowsNT asynchronous completion notification mechanism and the
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
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 (),
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 */
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
),
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 ()
415 if (this->proactor_
.handle_events () == -1)
416 ACE_ERROR_RETURN ((LM_ERROR
, ACE_TEXT ("%p\n"),
417 ACE_TEXT ("ACE_Proactor::handle_events")),
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)