(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.24.6.1 class HTTPAcceptorRep
 71 mike  1.2      {
 72 kumpf 1.24.6.1 public:
 73                    HTTPAcceptorRep(Boolean local)
 74                    {
 75                        if (local)
 76                        {
 77 kumpf 1.11     #ifdef PEGASUS_LOCAL_DOMAIN_SOCKET
 78 kumpf 1.24.6.1             address = reinterpret_cast<struct sockaddr*>(new struct sockaddr_un);
 79                            address_size = sizeof(struct sockaddr_un);
 80 kumpf 1.11     #else
 81 kumpf 1.24.6.1             PEGASUS_ASSERT(false);
 82 kumpf 1.11     #endif
 83 kumpf 1.24.6.1         }
 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.24.6.1 HTTPAcceptor::HTTPAcceptor(Monitor* monitor,
112                                           MessageQueue* outputMessageQueue,
113                                           Boolean localConnection,
114                                           Uint32 portNumber,
115 mike  1.2                                 SSLContext * sslcontext)
116 kumpf 1.24.6.1    : 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.24.6.1    // 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.24.6.1 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.24.6.1    _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.24.6.1    memset(_rep->address, 0, sizeof(*_rep->address));
225 kumpf 1.6      
226 kumpf 1.24.6.1    if (_localConnection)
227                   {
228 kumpf 1.11     #ifdef PEGASUS_LOCAL_DOMAIN_SOCKET
229 kumpf 1.24.6.1        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.24.6.1        PEGASUS_ASSERT(false);
236 kumpf 1.11     #endif
237 kumpf 1.24.6.1    }
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.24.6.1    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.24.6.1    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.24.6.1 
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.24.6.1    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.24.6.1    int address_size;
422 mike  1.2      #endif
423                
424 kumpf 1.24.6.1    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.24.6.1        PEGASUS_ASSERT(false);
431 mike  1.2      #endif
432 kumpf 1.24.6.1    }
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