(file) Return to HTTPAcceptor.cpp CVS log (file) (dir) Up to [Pegasus] / pegasus / src / Pegasus / Common

  1 mike  1.2 //%/////////////////////////////////////////////////////////////////////////////
  2           //
  3 kumpf 1.20 // Copyright (c) 2000, 2001, 2002 BMC Software, Hewlett-Packard Company, IBM,
  4 mike  1.2  // The Open Group, Tivoli Systems
  5            //
  6            // Permission is hereby granted, free of charge, to any person obtaining a copy
  7 kumpf 1.20 // of this software and associated documentation files (the "Software"), to
  8            // deal in the Software without restriction, including without limitation the
  9            // rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
 10 mike  1.2  // sell copies of the Software, and to permit persons to whom the Software is
 11            // furnished to do so, subject to the following conditions:
 12            // 
 13 kumpf 1.20 // THE ABOVE COPYRIGHT NOTICE AND THIS PERMISSION NOTICE SHALL BE INCLUDED IN
 14 mike  1.2  // ALL COPIES OR SUBSTANTIAL PORTIONS OF THE SOFTWARE. THE SOFTWARE IS PROVIDED
 15            // "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT
 16 kumpf 1.20 // LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR
 17            // PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
 18            // HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
 19 mike  1.2  // ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
 20            // WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
 21            //
 22            //==============================================================================
 23            //
 24            // Author: Mike Brasher (mbrasher@bmc.com)
 25            //
 26            // Modified By:
 27            //         Jenny Yu, Hewlett-Packard Company (jenny_yu@hp.com)
 28 kumpf 1.6  //         Nag Boranna, Hewlett-Packard Company (nagaraja_boranna@hp.com)
 29 mike  1.2  //
 30            //%/////////////////////////////////////////////////////////////////////////////
 31            
 32            #include "Config.h"
 33 kumpf 1.15 #include "Constants.h"
 34 mike  1.2  #include <iostream>
 35            #include "Socket.h"
 36            
 37            #ifdef PEGASUS_PLATFORM_WIN32_IX86_MSVC
 38 mday  1.12 #include <windows.h>
 39 mike  1.2  #else
 40            # include <cctype>
 41            # include <unistd.h>
 42            # include <cstdlib>
 43            # include <errno.h>
 44            # include <fcntl.h>
 45            # include <netdb.h>
 46            # include <netinet/in.h>
 47            # include <arpa/inet.h>
 48            # include <sys/socket.h>
 49 kumpf 1.11 # ifdef PEGASUS_LOCAL_DOMAIN_SOCKET
 50            #  include <sys/un.h>
 51            # endif
 52 mike  1.2  #endif
 53            
 54            #include "Socket.h"
 55            #include "TLS.h"
 56            #include "HTTPAcceptor.h"
 57            #include "HTTPConnection.h"
 58 kumpf 1.19 #include "Tracer.h"
 59 mike  1.2  
 60            PEGASUS_USING_STD;
 61            
 62            PEGASUS_NAMESPACE_BEGIN
 63            
 64            ////////////////////////////////////////////////////////////////////////////////
 65            //
 66            // HTTPAcceptorRep
 67            //
 68            ////////////////////////////////////////////////////////////////////////////////
 69            
 70 kumpf 1.25 class HTTPAcceptorRep
 71 mike  1.2  {
 72 kumpf 1.25 public:
 73                HTTPAcceptorRep(Boolean local)
 74                {
 75                    if (local)
 76                    {
 77 kumpf 1.11 #ifdef PEGASUS_LOCAL_DOMAIN_SOCKET
 78 kumpf 1.25             address = reinterpret_cast<struct sockaddr*>(new struct sockaddr_un);
 79                        address_size = sizeof(struct sockaddr_un);
 80 kumpf 1.11 #else
 81 kumpf 1.25             PEGASUS_ASSERT(false);
 82 kumpf 1.11 #endif
 83 kumpf 1.25         }
 84                    else
 85                    {
 86                        address = reinterpret_cast<struct sockaddr*>(new struct sockaddr_in);
 87                        address_size = sizeof(struct sockaddr_in);
 88                    }
 89                }
 90            
 91                struct sockaddr* address;
 92            
 93            #if defined(PEGASUS_PLATFORM_ZOS_ZSERIES_IBM)
 94               size_t address_size;
 95            #elif defined(PEGASUS_PLATFORM_AIX_RS_IBMCXX) || defined(PEGASUS_PLATFORM_LINUX_IX86_GNU) || defined(PEGASUS_PLATFORM_LINUX_GENERIC_GNU)
 96               socklen_t address_size;
 97            #else
 98               int address_size;
 99            #endif
100            
101                Sint32 socket;
102                Array<HTTPConnection*> connections;
103 mike  1.2  };
104            
105            ////////////////////////////////////////////////////////////////////////////////
106            //
107            // HTTPAcceptor
108            //
109            ////////////////////////////////////////////////////////////////////////////////
110            
111 kumpf 1.25 HTTPAcceptor::HTTPAcceptor(Monitor* monitor,
112                                       MessageQueue* outputMessageQueue,
113                                       Boolean localConnection,
114                                       Uint32 portNumber,
115 mike  1.2                             SSLContext * sslcontext)
116 kumpf 1.25    : Base(PEGASUS_QUEUENAME_HTTPACCEPTOR),  // ATTN: Need unique names?
117                 _monitor(monitor),
118                 _outputMessageQueue(outputMessageQueue),
119                 _rep(0),
120                 _entry_index(-1),
121                 _localConnection(localConnection),
122                 _portNumber(portNumber),
123                 _sslcontext(sslcontext)
124 mike  1.2  {
125 mday  1.7     Socket::initializeInterface();
126 mike  1.2  }
127            
128            HTTPAcceptor::~HTTPAcceptor()
129            {
130 mday  1.7     unbind();
131 kumpf 1.25    // ATTN: Is this correct in a multi-HTTPAcceptor server?
132 mday  1.7     Socket::uninitializeInterface();
133 mike  1.2  }
134            
135 mday  1.7  void HTTPAcceptor::handleEnqueue(Message *message)
136 mike  1.2  {
137 mday  1.7     if (! message)
138                  return;
139               
140               switch (message->getType())
141               {
142                  case SOCKET_MESSAGE:
143                  {
144            	 SocketMessage* socketMessage = (SocketMessage*)message;
145 mday  1.16 	 
146 mday  1.7  	 // If this is a connection request:
147            
148            	 if (socketMessage->socket == _rep->socket &&
149            	     socketMessage->events | SocketMessage::READ)
150            	 {
151            	    _acceptConnection();
152            	 }
153            	 else
154            	 {
155            	    // ATTN! this can't happen!
156            	 }
157            
158            	 break;
159                  }
160            
161                  case CLOSE_CONNECTION_MESSAGE:
162                  {
163            	 CloseConnectionMessage* closeConnectionMessage 
164            	    = (CloseConnectionMessage*)message;
165            
166            	 for (Uint32 i = 0, n = _rep->connections.size(); i < n; i++)
167 mday  1.7  	 {
168            	    HTTPConnection* connection = _rep->connections[i];	
169            	    Sint32 socket = connection->getSocket();
170 mike  1.2  
171 mday  1.7  	    if (socket == closeConnectionMessage->socket)
172 mike  1.2  	    {
173 mday  1.7  	       _monitor->unsolicitSocketMessages(socket);
174            	       _rep->connections.remove(i);
175 kumpf 1.17                delete connection;
176 mday  1.7  	       break;
177 mike  1.2  	    }
178 mday  1.7  	 }
179                  }
180 mike  1.2  
181 kumpf 1.10       default:
182                  // ATTN: need unexpected message error!
183 mday  1.7        break;
184               };
185 mike  1.2  
186 mday  1.7     delete message;
187            }
188 mike  1.2  
189            
190 mday  1.7  void HTTPAcceptor::handleEnqueue()
191            {
192               Message* message = dequeue();
193 mike  1.2  
194 mday  1.7     if (!message)
195                  return;
196               
197               handleEnqueue(message);
198 mike  1.2  
199            }
200            
201 kumpf 1.25 void HTTPAcceptor::bind()
202 mike  1.2  {
203 mday  1.7     if (_rep)
204 kumpf 1.23       throw BindFailedException("HTTPAcceptor already bound");
205 mike  1.2  
206 kumpf 1.25    _rep = new HTTPAcceptorRep(_localConnection);
207 mike  1.2  
208 mday  1.7     // bind address
209               _bind();
210 mike  1.2  
211 mday  1.7     return;
212 mike  1.2  }
213            
214            /**
215 mday  1.7     _bind - creates a new server socket and bind socket to the port address.
216 kumpf 1.11    If PEGASUS_LOCAL_DOMAIN_SOCKET is defined, the port number is ignored and
217               a domain socket is bound.
218 mike  1.2  */
219            void HTTPAcceptor::_bind()
220            {
221            
222 mday  1.7     // Create address:
223 mike  1.2  
224 kumpf 1.25    memset(_rep->address, 0, sizeof(*_rep->address));
225 kumpf 1.6  
226 kumpf 1.25    if (_localConnection)
227               {
228 kumpf 1.11 #ifdef PEGASUS_LOCAL_DOMAIN_SOCKET
229 kumpf 1.25        reinterpret_cast<struct sockaddr_un*>(_rep->address)->sun_family =
230                       AF_UNIX;
231                   strcpy(reinterpret_cast<struct sockaddr_un*>(_rep->address)->sun_path,
232                          PEGASUS_LOCAL_DOMAIN_SOCKET_PATH);
233                   ::unlink(reinterpret_cast<struct sockaddr_un*>(_rep->address)->sun_path);
234 kumpf 1.6  #else
235 kumpf 1.25        PEGASUS_ASSERT(false);
236 kumpf 1.11 #endif
237 kumpf 1.25    }
238               else
239               {
240                   reinterpret_cast<struct sockaddr_in*>(_rep->address)->sin_addr.s_addr =
241                       INADDR_ANY;
242                   reinterpret_cast<struct sockaddr_in*>(_rep->address)->sin_family =
243                       AF_INET;
244                   reinterpret_cast<struct sockaddr_in*>(_rep->address)->sin_port =
245                       htons(_portNumber);
246               }
247 mike  1.2  
248 mday  1.7     // Create socket:
249 mike  1.2      
250 kumpf 1.25    if (_localConnection)
251               {
252                   _rep->socket = socket(AF_UNIX, SOCK_STREAM, 0);
253               }
254               else
255               {
256                   _rep->socket = socket(PF_INET, SOCK_STREAM, IPPROTO_TCP);
257               }
258 mike  1.2  
259 mday  1.7     if (_rep->socket < 0)
260               {
261                  delete _rep;
262                  _rep = 0;
263 kumpf 1.23       throw BindFailedException("Failed to create socket");
264 mday  1.7     }
265            
266               //
267               // Set the socket option SO_REUSEADDR to reuse the socket address so
268               // that we can rebind to a new socket using the same address when we
269               // need to resume the cimom as a result of a timeout during a Shutdown
270               // operation.
271               //
272               int opt=1;
273               if (setsockopt(_rep->socket, SOL_SOCKET, SO_REUSEADDR,
274            		  (char *)&opt, sizeof(opt)) < 0)
275               {
276                  delete _rep;
277                  _rep = 0;
278 kumpf 1.23       throw BindFailedException("Failed to set socket option");
279 mday  1.7     }
280            
281               // Bind socket to port:
282            
283 kumpf 1.25    if (::bind(_rep->socket, _rep->address, _rep->address_size) < 0)
284 mday  1.7     {
285                  Socket::close(_rep->socket);
286                  delete _rep;
287                  _rep = 0;
288 kumpf 1.23       throw BindFailedException("Failed to bind socket");
289 mday  1.7     }
290            
291 kumpf 1.11    // Set up listening on the given socket:
292 mday  1.7  
293               int const MAX_CONNECTION_QUEUE_LENGTH = 5;
294            
295               if (listen(_rep->socket, MAX_CONNECTION_QUEUE_LENGTH) < 0)
296               {
297                  Socket::close(_rep->socket);
298                  delete _rep;
299                  _rep = 0;
300 kumpf 1.23       throw BindFailedException("Failed to bind socket");
301 mday  1.7     }
302            
303               // Register to receive SocketMessages on this socket:
304            
305 mday  1.21    if ( -1 == ( _entry_index = _monitor->solicitSocketMessages(
306 mday  1.7  	  _rep->socket,
307            	  SocketMessage::READ | SocketMessage::EXCEPTION,
308 mday  1.16 	  getQueueId(), 
309 mday  1.21 	  Monitor::ACCEPTOR)))
310 mday  1.7     {
311                  Socket::close(_rep->socket);
312                  delete _rep;
313                  _rep = 0;
314 kumpf 1.23       throw BindFailedException("Failed to solicit socket messaeges");
315 mday  1.7     }
316 mike  1.2  }
317            
318            /**
319 mday  1.7     closeConnectionSocket - close the server listening socket to disallow
320               new client connections.
321 mike  1.2  */
322            void HTTPAcceptor::closeConnectionSocket()
323            {
324 mday  1.7     if (_rep)
325               {
326                  // unregister the socket
327                  _monitor->unsolicitSocketMessages(_rep->socket);
328            
329                  // close the socket
330                  Socket::close(_rep->socket);
331               }
332 mike  1.2  }
333            
334            /**
335 mday  1.7     reopenConnectionSocket - creates a new server socket.
336 mike  1.2  */
337            void HTTPAcceptor::reopenConnectionSocket()
338            {
339 mday  1.7     if (_rep)
340               {
341                  _bind();
342               }
343 mike  1.2  }
344            
345            /**
346 mday  1.7     getOutstandingRequestCount - returns the number of outstanding requests.
347 mike  1.2  */
348            Uint32 HTTPAcceptor::getOutstandingRequestCount()
349            {
350 mday  1.7     if (_rep->connections.size() > 0)
351               {
352                  HTTPConnection* connection = _rep->connections[0];	
353                  return(connection->getRequestCount());
354               }
355               else
356               {
357                  return(0);
358               }
359 mike  1.2  }
360            
361            void HTTPAcceptor::unbind()
362            {
363 mday  1.7     if (_rep)
364               {
365                  Socket::close(_rep->socket);
366 kumpf 1.25 
367                  if (_localConnection)
368                  {
369            #ifdef PEGASUS_LOCAL_DOMAIN_SOCKET
370                     ::unlink(
371                         reinterpret_cast<struct sockaddr_un*>(_rep->address)->sun_path);
372            #else
373                     PEGASUS_ASSERT(false);
374            #endif
375                  }
376            
377 mday  1.7        delete _rep;
378                  _rep = 0;
379               }
380 mike  1.2  }
381            
382            void HTTPAcceptor::destroyConnections()
383            {
384 mday  1.7     // For each connection created by this object:
385 mike  1.2  
386 mday  1.7     for (Uint32 i = 0, n = _rep->connections.size(); i < n; i++)
387               {
388                  HTTPConnection* connection = _rep->connections[i];	
389                  Sint32 socket = connection->getSocket();
390 mike  1.2  
391 mday  1.7        // Unsolicit SocketMessages:
392 mike  1.2  
393 mday  1.7        _monitor->unsolicitSocketMessages(socket);
394 mike  1.2  
395 mday  1.7        // Destroy the connection (causing it to close):
396 mike  1.2  
397 kumpf 1.17       while (connection->refcount.value()) { }
398 mday  1.7        delete connection;
399               }
400 mike  1.2  
401 mday  1.7     _rep->connections.clear();
402 mike  1.2  }
403            
404            void HTTPAcceptor::_acceptConnection()
405            {
406 mday  1.7     // This function cannot be called on an invalid socket!
407 mike  1.2  
408 mday  1.7     PEGASUS_ASSERT(_rep != 0);
409 mike  1.2  
410 mday  1.7     if (!_rep)
411                  return;
412 mike  1.2  
413 mday  1.7     // Accept the connection (populate the address):
414 mike  1.2  
415 kumpf 1.25    struct sockaddr* accept_address;
416            #if defined(PEGASUS_PLATFORM_ZOS_ZSERIES_IBM)
417               size_t address_size;
418            #elif defined(PEGASUS_PLATFORM_AIX_RS_IBMCXX) || defined(PEGASUS_PLATFORM_LINUX_IX86_GNU) || defined(PEGASUS_PLATFORM_LINUX_GENERIC_GNU)
419               socklen_t address_size;
420 mike  1.2  #else
421 kumpf 1.25    int address_size;
422 mike  1.2  #endif
423            
424 kumpf 1.25    if (_localConnection)
425               {
426            #ifdef PEGASUS_LOCAL_DOMAIN_SOCKET
427                   accept_address = reinterpret_cast<struct sockaddr*>(new struct sockaddr_un);
428                   address_size = sizeof(struct sockaddr_un);
429 mike  1.2  #else
430 kumpf 1.25        PEGASUS_ASSERT(false);
431 mike  1.2  #endif
432 kumpf 1.25    }
433               else
434               {
435                   accept_address = reinterpret_cast<struct sockaddr*>(new struct sockaddr_in);
436                   address_size = sizeof(struct sockaddr_in);
437               }
438            
439               Sint32 socket = accept(_rep->socket, accept_address, &address_size);
440            
441               delete accept_address;
442 mike  1.2  
443 mday  1.7     if (socket < 0)
444               {
445 kumpf 1.19        PEG_TRACE_STRING(TRC_HTTP, Tracer::LEVEL2,
446                                    "HTTPAcceptor: accept() failed");
447 mday  1.7        return;
448               }
449 mike  1.2  
450 mday  1.7     // Create a new conection and add it to the connection list:
451 mike  1.2  
452 mday  1.7     MP_Socket * mp_socket = new MP_Socket(socket, _sslcontext);
453 kumpf 1.19    if (mp_socket->accept() < 0) 
454               {
455                   PEG_TRACE_STRING(TRC_HTTP, Tracer::LEVEL2,
456                                    "HTTPAcceptor: SSL_accept() failed");
457 mday  1.7        return;
458               }
459 mike  1.2  
460 mday  1.7     HTTPConnection* connection = new HTTPConnection(
461 mday  1.16       _monitor, mp_socket, this, static_cast<MessageQueue *>(_outputMessageQueue));
462 mike  1.2  
463 mday  1.7     // Solicit events on this new connection's socket:
464 mday  1.21    int index;
465               
466 mday  1.22    if (-1 ==  (index = _monitor->solicitSocketMessages(
467 mday  1.7  	  socket,
468            	  SocketMessage::READ | SocketMessage::EXCEPTION,
469 mday  1.21 	  connection->getQueueId(), Monitor::CONNECTION)) )
470 mday  1.7     {
471                  delete connection;
472                  Socket::close(socket);
473               }
474 mike  1.2  
475 mday  1.7     // Save the socket for cleanup later:
476 mday  1.21    connection->_entry_index = index;
477               
478 mday  1.7     _rep->connections.append(connection);
479 mike  1.2  }
480            
481            PEGASUS_NAMESPACE_END

No CVS admin address has been configured
Powered by
ViewCVS 0.9.2