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

  1 karl  1.91 //%2006////////////////////////////////////////////////////////////////////////
  2            //
  3            // Copyright (c) 2000, 2001, 2002 BMC Software; Hewlett-Packard Development
  4            // Company, L.P.; IBM Corp.; The Open Group; Tivoli Systems.
  5            // Copyright (c) 2003 BMC Software; Hewlett-Packard Development Company, L.P.;
  6            // IBM Corp.; EMC Corporation, The Open Group.
  7            // Copyright (c) 2004 BMC Software; Hewlett-Packard Development Company, L.P.;
  8            // IBM Corp.; EMC Corporation; VERITAS Software Corporation; The Open Group.
  9            // Copyright (c) 2005 Hewlett-Packard Development Company, L.P.; IBM Corp.;
 10            // EMC Corporation; VERITAS Software Corporation; The Open Group.
 11            // Copyright (c) 2006 Hewlett-Packard Development Company, L.P.; IBM Corp.;
 12            // EMC Corporation; Symantec Corporation; The Open Group.
 13            //
 14            // Permission is hereby granted, free of charge, to any person obtaining a copy
 15            // of this software and associated documentation files (the "Software"), to
 16            // deal in the Software without restriction, including without limitation the
 17            // rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
 18            // sell copies of the Software, and to permit persons to whom the Software is
 19            // furnished to do so, subject to the following conditions:
 20            //
 21            // THE ABOVE COPYRIGHT NOTICE AND THIS PERMISSION NOTICE SHALL BE INCLUDED IN
 22 karl  1.91 // ALL COPIES OR SUBSTANTIAL PORTIONS OF THE SOFTWARE. THE SOFTWARE IS PROVIDED
 23            // "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT
 24            // LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR
 25            // PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
 26            // HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
 27            // ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
 28            // WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
 29            //
 30            //==============================================================================
 31            //
 32            //%/////////////////////////////////////////////////////////////////////////////
 33            
 34            #include "Config.h"
 35            #include "Constants.h"
 36            #include <iostream>
 37            
 38            #include "Network.h"
 39            #include "Socket.h"
 40            #include "TLS.h"
 41            #include "HTTPAcceptor.h"
 42            #include "HTTPConnection.h"
 43 dave.sudlik 1.101 #include "HostAddress.h"
 44 karl        1.91  #include "Tracer.h"
 45 kumpf       1.93  #include <Pegasus/Common/MessageLoader.h>
 46 karl        1.91  
 47 ouyang.jian 1.102 #ifdef PEGASUS_OS_PASE
 48                   # include <as400_protos.h>
 49                   # include <Pegasus/Common/PaseCcsid.h>
 50                   #endif
 51                   
 52 karl        1.91  PEGASUS_USING_STD;
 53                   
 54                   PEGASUS_NAMESPACE_BEGIN
 55                   
 56                   
 57 mateus.baur 1.103 static int _maxConnectionQueueLength = -1;
 58 karl        1.91  
 59                   ////////////////////////////////////////////////////////////////////////////////
 60                   //
 61                   // HTTPAcceptorRep
 62                   //
 63                   ////////////////////////////////////////////////////////////////////////////////
 64                   
 65                   class HTTPAcceptorRep
 66                   {
 67                   public:
 68 dave.sudlik 1.101     HTTPAcceptorRep(Uint16 connectionType)
 69 karl        1.91      {
 70 dave.sudlik 1.101         if (connectionType == HTTPAcceptor::LOCAL_CONNECTION)
 71 karl        1.91          {
 72                   #ifndef PEGASUS_DISABLE_LOCAL_DOMAIN_SOCKET
 73 kumpf       1.92              address =
 74                                   reinterpret_cast<struct sockaddr*>(new struct sockaddr_un);
 75 karl        1.91              address_size = sizeof(struct sockaddr_un);
 76                   #else
 77                               PEGASUS_ASSERT(false);
 78                   #endif
 79                           }
 80 dave.sudlik 1.101 #ifdef PEGASUS_ENABLE_IPV6
 81                           else if (connectionType == HTTPAcceptor::IPV6_CONNECTION)
 82                           {
 83                               address =
 84                                   reinterpret_cast<struct sockaddr*>(new struct sockaddr_in6);
 85                               address_size = sizeof(struct sockaddr_in6);
 86                           }
 87                   #endif
 88                           else if (connectionType == HTTPAcceptor::IPV4_CONNECTION)
 89 karl        1.91          {
 90 kumpf       1.92              address =
 91                                   reinterpret_cast<struct sockaddr*>(new struct sockaddr_in);
 92 karl        1.91              address_size = sizeof(struct sockaddr_in);
 93                           }
 94 dave.sudlik 1.101         else
 95                           {
 96                               PEGASUS_ASSERT(false);
 97 karl        1.91      }
 98 dave.sudlik 1.101     }
 99                   
100 karl        1.91      ~HTTPAcceptorRep()
101                       {
102 kumpf       1.116         closeSocket();
103 karl        1.91          delete address;
104                       }
105 kumpf       1.116 
106                       void closeSocket()
107                       {
108                           Socket::close(socket);
109                       }
110                   
111 karl        1.91      struct sockaddr* address;
112                   
113                       SocketLength address_size;
114                       Mutex _connection_mut;
115                   
116                       SocketHandle socket;
117                       Array<HTTPConnection*> connections;
118                   };
119                   
120                   
121                   ////////////////////////////////////////////////////////////////////////////////
122                   //
123                   // HTTPAcceptor
124                   //
125                   ////////////////////////////////////////////////////////////////////////////////
126                   
127                   HTTPAcceptor::HTTPAcceptor(Monitor* monitor,
128                                              MessageQueue* outputMessageQueue,
129 dave.sudlik 1.101                            Uint16 connectionType,
130 karl        1.91                             Uint32 portNumber,
131                                              SSLContext * sslcontext,
132                                              ReadWriteSem* sslContextObjectLock)
133                      : Base(PEGASUS_QUEUENAME_HTTPACCEPTOR),  // ATTN: Need unique names?
134                        _monitor(monitor),
135                        _outputMessageQueue(outputMessageQueue),
136                        _rep(0),
137                        _entry_index(-1),
138 dave.sudlik 1.101      _connectionType(connectionType),
139 karl        1.91       _portNumber(portNumber),
140                        _sslcontext(sslcontext),
141 dave.sudlik 1.108      _sslContextObjectLock(sslContextObjectLock),
142                        _idleConnectionTimeoutSeconds(0)
143 karl        1.91  {
144 ouyang.jian 1.121    PEGASUS_ASSERT(!_sslcontext == !_sslContextObjectLock);
145 karl        1.91     Socket::initializeInterface();
146                   
147                      /*
148 mateus.baur 1.103         Platforms interpret the value of _maxConnectionQueueLength
149 kumpf       1.92          differently.  Some platforms interpret the value literally, while
150                           others multiply a fudge factor. When the server is under stress from
151                           multiple clients with multiple requests, toggling this number may
152                           prevent clients from being dropped.  Instead of hard coding the
153                           value, we allow an environment variable to be set which specifies a
154                           number greater than the maximum concurrent client connections
155                           possible.  If this environment var is not specified, then
156 mateus.baur 1.103         _maxConnectionQueueLength = 15.
157 karl        1.91     */
158                   
159 kumpf       1.92  //To engage runtime backlog queue length: uncomment the following block AND
160 mateus.baur 1.103 //comment out the line _maxConnectionQueueLength = 15
161 karl        1.91  
162                   /*
163 mateus.baur 1.103     if (_maxConnectionQueueLength == -1)
164 kumpf       1.92      {
165                           const char* env = getenv("PEGASUS_MAX_BACKLOG_CONNECTION_QUEUE");
166                           if (!env)
167                           {
168 mateus.baur 1.103             _maxConnectionQueueLength = 15;
169 kumpf       1.92          }
170                           else
171                           {
172                               char* end = NULL;
173 mateus.baur 1.103             _maxConnectionQueueLength = strtol(env, &end, 10);
174 kumpf       1.92              if (*end)
175 mateus.baur 1.103                 _maxConnectionQueueLength = 15;
176                               cout << " _maxConnectionQueueLength = " <<
177                                   _maxConnectionQueueLength << endl;
178 kumpf       1.92          }
179 karl        1.91      }
180                   */
181 mateus.baur 1.103 #ifdef PEGASUS_WMIMAPPER
182                       //The WMI Mapper can be used as a proxy to multiple WMI Servers.
183                       //If a client application simultaneously initiates connections
184                       //to many Windows systems, many of these connections may be routed
185                       //to a single WMI Mapper. A larger _maxConnectionQueueLength
186                       //value is required to allow these connections to be initiated
187                       //successfully.
188                       _maxConnectionQueueLength = 40;
189                   #else
190                       _maxConnectionQueueLength = 15;
191                   #endif
192 karl        1.91  }
193                   
194                   HTTPAcceptor::~HTTPAcceptor()
195                   {
196 kumpf       1.92      destroyConnections();
197                       unbind();
198                       // ATTN: Is this correct in a multi-HTTPAcceptor server?
199                       Socket::uninitializeInterface();
200 karl        1.91  }
201                   
202                   void HTTPAcceptor::handleEnqueue(Message *message)
203                   {
204 kumpf       1.92      if (!message)
205                          return;
206                   
207                       PEGASUS_ASSERT(_rep != 0);
208                       switch (message->getType())
209                       {
210                           case SOCKET_MESSAGE:
211                           {
212                               SocketMessage* socketMessage = (SocketMessage*)message;
213                   
214                               // If this is a connection request:
215 sushma.fernandes 1.117             PEGASUS_ASSERT(socketMessage->socket == _rep->socket);
216 kumpf            1.92  
217 sushma.fernandes 1.117             PEGASUS_ASSERT(socketMessage->events & SocketMessage::READ);
218                        
219                                    _acceptConnection();
220 karl             1.91  
221 sushma.fernandes 1.117             break;
222                                }
223 kumpf            1.92  
224                               case CLOSE_CONNECTION_MESSAGE:
225                               {
226                                   CloseConnectionMessage* closeConnectionMessage =
227                                       (CloseConnectionMessage*)message;
228                        
229                                   AutoMutex autoMut(_rep->_connection_mut);
230                        
231                                   for (Uint32 i = 0, n = _rep->connections.size(); i < n; i++)
232                                   {
233                                       HTTPConnection* connection = _rep->connections[i];
234                                       SocketHandle socket = connection->getSocket();
235                        
236                                       if (socket == closeConnectionMessage->socket)
237                                       {
238                                           _monitor->unsolicitSocketMessages(socket);
239                                           _rep->connections.remove(i);
240                                           delete connection;
241                                           break;
242                                       }
243                                   }
244 karl             1.91  
245 kumpf            1.92             break;
246                               }
247 karl             1.91  
248 kumpf            1.92         default:
249 sushma.fernandes 1.117            PEGASUS_ASSERT(false);
250 kumpf            1.92             break;
251                            }
252 karl             1.91  
253 kumpf            1.92      delete message;
254 karl             1.91  }
255                        
256                        
257                        void HTTPAcceptor::handleEnqueue()
258                        {
259 kumpf            1.92      Message* message = dequeue();
260                            handleEnqueue(message);
261 karl             1.91  }
262                        
263                        void HTTPAcceptor::bind()
264                        {
265 kumpf            1.92      if (_rep)
266                            {
267                                MessageLoaderParms parms("Common.HTTPAcceptor.ALREADY_BOUND",
268                                    "HTTPAcceptor already bound");
269                                throw BindFailedException(parms);
270                            }
271 karl             1.91  
272 dave.sudlik      1.101     _rep = new HTTPAcceptorRep(_connectionType);
273 karl             1.91  
274 kumpf            1.92      // bind address
275                            _bind();
276 karl             1.91  }
277                        
278                        /**
279 kumpf            1.92      _bind - creates a new server socket and bind socket to the port address.
280                            If PEGASUS_DISABLE_LOCAL_DOMAIN_SOCKET is not defined, the port number is
281                            ignored and a domain socket is bound.
282 karl             1.91  */
283                        void HTTPAcceptor::_bind()
284                        {
285 ouyang.jian      1.102 #ifdef PEGASUS_OS_PASE
286                            // bind need ccsid is 819 
287                            int orig_ccsid;
288                            orig_ccsid = _SETCCSID(-1);
289                            if (orig_ccsid == -1)
290                            {
291 mike             1.122.4.1         PEG_TRACE_STRING(TRC_DISCARDED_DATA, Tracer::LEVEL1,
292 ouyang.jian      1.102                 String("HTTPAcceptor::_bind: Can not get current PASE CCSID."));
293                                    orig_ccsid = 1208;
294                                }
295                                PaseCcsid ccsid(819, orig_ccsid);
296                            #endif
297                            
298 kumpf            1.92          PEGASUS_ASSERT(_rep != 0);
299                                // Create address:
300 dave.sudlik      1.101         memset(_rep->address, 0, _rep->address_size);
301 karl             1.91      
302 dave.sudlik      1.101         if (_connectionType == LOCAL_CONNECTION)
303 kumpf            1.92          {
304 karl             1.91      #ifndef PEGASUS_DISABLE_LOCAL_DOMAIN_SOCKET
305 kumpf            1.100             //
306                                    // Make sure the local domain socket can be owned by the cimserver
307                                    // user.  Otherwise, the bind may fail with a vague "bind failed"
308                                    // error.
309                                    //
310                                    if (System::exists(PEGASUS_LOCAL_DOMAIN_SOCKET_PATH))
311                                    {
312                                        if (!System::removeFile(PEGASUS_LOCAL_DOMAIN_SOCKET_PATH))
313                                        {
314                                            throw CannotRemoveFile(PEGASUS_LOCAL_DOMAIN_SOCKET_PATH);
315                                        }
316                                    }
317                            
318 kumpf            1.92              reinterpret_cast<struct sockaddr_un*>(_rep->address)->sun_family =
319                                        AF_UNIX;
320                                    strcpy(reinterpret_cast<struct sockaddr_un*>(_rep->address)->sun_path,
321                                        PEGASUS_LOCAL_DOMAIN_SOCKET_PATH);
322 karl             1.91      #else
323 kumpf            1.92              PEGASUS_ASSERT(false);
324 karl             1.91      #endif
325 kumpf            1.92          }
326 dave.sudlik      1.101     #ifdef PEGASUS_ENABLE_IPV6
327                                else if (_connectionType == IPV6_CONNECTION)
328                                {
329                                    reinterpret_cast<struct sockaddr_in6*>(_rep->address)->sin6_addr =
330                                        in6addr_any;
331                                    reinterpret_cast<struct sockaddr_in6*>(_rep->address)->sin6_family =
332                                        AF_INET6;
333                                    reinterpret_cast<struct sockaddr_in6*>(_rep->address)->sin6_port =
334                                        htons(_portNumber);
335                                }
336                            #endif
337                                else if(_connectionType == IPV4_CONNECTION)
338 kumpf            1.92          {
339                                    reinterpret_cast<struct sockaddr_in*>(_rep->address)->sin_addr.s_addr =
340                                        INADDR_ANY;
341                                    reinterpret_cast<struct sockaddr_in*>(_rep->address)->sin_family =
342                                        AF_INET;
343                                    reinterpret_cast<struct sockaddr_in*>(_rep->address)->sin_port =
344                                        htons(_portNumber);
345                                }
346 dave.sudlik      1.101         else
347                                {
348                                    PEGASUS_ASSERT(false);
349                                }
350 kumpf            1.92      
351                                // Create socket:
352                            
353 dave.sudlik      1.101         if (_connectionType == LOCAL_CONNECTION)
354 kumpf            1.92          {
355                                    _rep->socket = Socket::createSocket(AF_UNIX, SOCK_STREAM, 0);
356                                }
357 dave.sudlik      1.101     #ifdef PEGASUS_ENABLE_IPV6
358                                else if (_connectionType == IPV6_CONNECTION)
359                                {
360                                    _rep->socket = Socket::createSocket(PF_INET6, SOCK_STREAM, IPPROTO_TCP);
361                                }
362                            #endif
363                                else if (_connectionType == IPV4_CONNECTION)
364                                {
365                                    _rep->socket = Socket::createSocket(PF_INET, SOCK_STREAM, IPPROTO_TCP);
366                                }
367 kumpf            1.92          else
368                                {
369 dave.sudlik      1.101             PEGASUS_ASSERT(false);
370 kumpf            1.92          }
371                            
372                                if (_rep->socket < 0)
373                                {
374                                    delete _rep;
375                                    _rep = 0;
376                                    MessageLoaderParms parms("Common.HTTPAcceptor.FAILED_CREATE_SOCKET",
377                                        "Failed to create socket");
378                                    throw BindFailedException(parms);
379                                }
380 karl             1.91      
381 kumpf            1.109         Socket::disableBlocking(_rep->socket);
382 karl             1.91      
383                            // set the close-on-exec bit for this file handle.
384                            // any unix that forks needs this bit set.
385                            #if !defined PEGASUS_OS_TYPE_WINDOWS && !defined(PEGASUS_OS_VMS)
386 kumpf            1.92          int sock_flags;
387                                if ((sock_flags = fcntl(_rep->socket, F_GETFD, 0)) < 0)
388                                {
389 mike             1.122.4.1         PEG_TRACE_CSTRING(TRC_DISCARDED_DATA, Tracer::LEVEL1,
390 kumpf            1.92                  "HTTPAcceptor::_bind: fcntl(F_GETFD) failed");
391                                }
392                                else
393                                {
394                                    sock_flags |= FD_CLOEXEC;
395                                    if (fcntl(_rep->socket, F_SETFD, sock_flags) < 0)
396                                    {
397 mike             1.122.4.1             PEG_TRACE_CSTRING(TRC_DISCARDED_DATA, Tracer::LEVEL1,
398 kumpf            1.92                      "HTTPAcceptor::_bind: fcntl(F_SETFD) failed");
399                                    }
400                                }
401                            #endif
402                            
403                            
404                                //
405                                // Set the socket option SO_REUSEADDR to reuse the socket address so
406                                // that we can rebind to a new socket using the same address when we
407                                // need to resume the cimom as a result of a timeout during a Shutdown
408                                // operation.
409                                //
410                                int opt=1;
411                                if (setsockopt(_rep->socket, SOL_SOCKET, SO_REUSEADDR,
412                                        (char *)&opt, sizeof(opt)) < 0)
413                                {
414                                    delete _rep;
415                                    _rep = 0;
416                                    MessageLoaderParms parms("Common.HTTPAcceptor.FAILED_SET_SOCKET_OPTION",
417                                        "Failed to set socket option");
418                                    throw BindFailedException(parms);
419 kumpf            1.92          }
420                            
421                            
422                                //
423                                // Bind socket to port:
424                                //
425                                if (::bind(_rep->socket, _rep->address, _rep->address_size) < 0)
426                                {
427 thilo.boehm      1.115             MessageLoaderParms parms(
428                                        "Common.HTTPAcceptor.FAILED_BIND_SOCKET_DETAIL",
429                                        "Failed to bind socket on port $0: $1.",
430                                        _portNumber, PEGASUS_SYSTEM_NETWORK_ERRORMSG_NLS);
431                            
432 kumpf            1.92              delete _rep;
433                                    _rep = 0;
434                                    throw BindFailedException(parms);
435                                }
436                            
437                            
438                                //
439                                // Get the actual port value used if the caller specified a port value of 0.
440                                //
441                                if (_portNumber == 0)
442                                {
443                                    sockaddr_in buf;
444                                    SocketLength bufSize = sizeof(buf);
445                                    if (getsockname(_rep->socket, reinterpret_cast<sockaddr *>(&buf),
446                                            &bufSize) == 0 )
447                                    {
448                                        _portNumber = ntohs(buf.sin_port);
449                                    }
450                                }
451                            
452                            
453 kumpf            1.92          //
454                                // Change permissions on Linux local domain socket to allow writes by
455                                // others.
456                                //
457 karl             1.91      #if !defined(PEGASUS_DISABLE_LOCAL_DOMAIN_SOCKET) && \
458 kumpf            1.92           (defined(PEGASUS_PLATFORM_LINUX_GENERIC_GNU) || \
459 ouyang.jian      1.118           defined(PEGASUS_PLATFORM_ZOS_ZSERIES_IBM) || \
460                                  defined(PEGASUS_OS_PASE))
461 dave.sudlik      1.101         if (_connectionType == LOCAL_CONNECTION)
462 kumpf            1.92          {
463                                    if (::chmod(PEGASUS_LOCAL_DOMAIN_SOCKET_PATH,
464                                            S_IRUSR | S_IWUSR | S_IXUSR |
465                                            S_IRGRP | S_IWGRP | S_IXGRP |
466                                            S_IROTH | S_IWOTH | S_IXOTH ) < 0 )
467                                    {
468 thilo.boehm      1.115                 MessageLoaderParms parms(
469                                            "Common.HTTPAcceptor.FAILED_SET_LDS_FILE_OPTION",
470                                            "Failed to set permission on local domain socket {0}: {1}.",
471                                            PEGASUS_LOCAL_DOMAIN_SOCKET_PATH,
472                                            PEGASUS_SYSTEM_ERRORMSG_NLS );
473                            
474 kumpf            1.92                  delete _rep;
475                                        _rep = 0;
476                                        throw BindFailedException(parms);
477                                    }
478                                }
479                            #endif
480                            
481                                // Set up listening on the given socket:
482                            
483 mateus.baur      1.103         //int const _maxConnectionQueueLength = 15;
484 kumpf            1.92      
485 thilo.boehm      1.115         if (::listen(_rep->socket, _maxConnectionQueueLength) < 0)
486 kumpf            1.92          {
487 thilo.boehm      1.115             MessageLoaderParms parms(
488                                        "Common.HTTPAcceptor.FAILED_LISTEN_SOCKET",
489                                        "Failed to listen on socket {0}: {1}.",
490                                        (int)_rep->socket,PEGASUS_SYSTEM_NETWORK_ERRORMSG_NLS );
491                                    
492 kumpf            1.92              delete _rep;
493                                    _rep = 0;
494                                    throw BindFailedException(parms);
495                                }
496                            
497                                // Register to receive SocketMessages on this socket:
498                            
499                                if (-1 == ( _entry_index = _monitor->solicitSocketMessages(
500                                        _rep->socket,
501                                        SocketMessage::READ | SocketMessage::EXCEPTION,
502                                        getQueueId(),
503 kumpf            1.107                 MonitorEntry::TYPE_ACCEPTOR)))
504 kumpf            1.92          {
505                                    delete _rep;
506                                    _rep = 0;
507                                    MessageLoaderParms parms(
508                                        "Common.HTTPAcceptor.FAILED_SOLICIT_SOCKET_MESSAGES",
509                                        "Failed to solicit socket messaeges");
510                                    throw BindFailedException(parms);
511                                }
512 karl             1.91      }
513                            
514                            /**
515 kumpf            1.92          closeConnectionSocket - close the server listening socket to disallow
516                                new client connections.
517 karl             1.91      */
518                            void HTTPAcceptor::closeConnectionSocket()
519                            {
520 kumpf            1.92          if (_rep)
521                                {
522                                    // unregister the socket
523                            
524                                    // ATTN - comment out - see CIMServer::stopClientConnection()
525                                    //_monitor->unsolicitSocketMessages(_rep->socket);
526                            
527                                    // close the socket
528 kumpf            1.116             _rep->closeSocket();
529 kumpf            1.92              // Unlink Local Domain Socket Bug# 3312
530 dave.sudlik      1.101             if (_connectionType == LOCAL_CONNECTION)
531 kumpf            1.92              {
532 karl             1.91      #ifndef PEGASUS_DISABLE_LOCAL_DOMAIN_SOCKET
533 mike             1.122.4.1             PEG_TRACE_CSTRING(TRC_HTTP, Tracer::LEVEL3,
534 kumpf            1.92                      "HTTPAcceptor::closeConnectionSocket Unlinking local "
535                                                "connection.");
536                                        ::unlink(
537                                            reinterpret_cast<struct sockaddr_un*>(_rep->address)->sun_path);
538 karl             1.91      #else
539 kumpf            1.92                  PEGASUS_ASSERT(false);
540 karl             1.91      #endif
541 kumpf            1.92              }
542                                }
543                                else
544                                {
545 sushma.fernandes 1.117             PEG_TRACE_CSTRING(TRC_HTTP, Tracer::LEVEL2,
546 kumpf            1.92                  "HTTPAcceptor::closeConnectionSocket failure _rep is null.");
547                                }
548 karl             1.91      }
549                            
550                            /**
551                               reopenConnectionSocket - creates a new server socket.
552                            */
553                            void HTTPAcceptor::reopenConnectionSocket()
554                            {
555 kumpf            1.92          if (_rep)
556                                {
557                                    _bind();
558                                }
559                                else
560                                {
561 mike             1.122.4.1         PEG_TRACE_CSTRING(TRC_DISCARDED_DATA, Tracer::LEVEL1,
562 kumpf            1.92                  "HTTPAcceptor::reopenConnectionSocket failure _rep is null.");
563                                }
564 karl             1.91      }
565                            
566                            
567                            /**
568                               reconnectConnectionSocket - creates a new server socket.
569                            */
570                            void HTTPAcceptor::reconnectConnectionSocket()
571                            {
572 kumpf            1.92          if (_rep)
573                                {
574                                    // unregister the socket
575                                    _monitor->unsolicitSocketMessages(_rep->socket);
576                                    // close the socket
577 kumpf            1.116             _rep->closeSocket();
578                                    // Unlink Local Domain Socket
579 dave.sudlik      1.101             if (_connectionType == LOCAL_CONNECTION)
580 kumpf            1.92              {
581 karl             1.91      #ifndef PEGASUS_DISABLE_LOCAL_DOMAIN_SOCKET
582 mike             1.122.4.1             PEG_TRACE_CSTRING(TRC_HTTP, Tracer::LEVEL3,
583 kumpf            1.92                      "HTTPAcceptor::reconnectConnectionSocket Unlinking local "
584                                                "connection." );
585                                        ::unlink(
586                                            reinterpret_cast<struct sockaddr_un*>(_rep->address)->sun_path);
587 karl             1.91      #else
588 kumpf            1.92                  PEGASUS_ASSERT(false);
589 karl             1.91      #endif
590 kumpf            1.92              }
591                                    // open the socket
592                                    _bind();
593                                }
594                                else
595                                {
596 mike             1.122.4.1         PEG_TRACE_CSTRING(TRC_DISCARDED_DATA, Tracer::LEVEL1,
597 kumpf            1.92                  "HTTPAcceptor::reconnectConnectionSocket failure _rep is null.");
598                                }
599 karl             1.91      }
600                            
601                            /**
602 kumpf            1.92          getOutstandingRequestCount - returns the number of outstanding requests.
603 karl             1.91      */
604                            Uint32 HTTPAcceptor::getOutstandingRequestCount() const
605                            {
606 kumpf            1.92          Uint32 count = 0;
607                                if (_rep)
608                                {
609                                    AutoMutex autoMut(_rep->_connection_mut);
610 kumpf            1.110             for (Uint32 i = 0, n = _rep->connections.size(); i < n; i++)
611 kumpf            1.92              {
612 kumpf            1.110                 HTTPConnection* connection = _rep->connections[i];
613                                        if (connection->isResponsePending())
614                                        {
615                                            count++;
616                                        }
617 kumpf            1.92              }
618                                }
619                                return count;
620 karl             1.91      }
621                            
622                            
623                            /**
624                                getPortNumber - returns the port number used for the connection
625                            */
626                            Uint32 HTTPAcceptor::getPortNumber() const
627                            {
628                                return _portNumber;
629                            }
630                            
631                            void HTTPAcceptor::setSocketWriteTimeout(Uint32 socketWriteTimeout)
632                            {
633                                _socketWriteTimeout = socketWriteTimeout;
634                            }
635                            
636 dave.sudlik      1.108     void HTTPAcceptor::setIdleConnectionTimeout(Uint32 idleConnectionTimeoutSeconds)
637                            {
638                                _idleConnectionTimeoutSeconds = idleConnectionTimeoutSeconds;
639                            }
640                            
641 karl             1.91      void HTTPAcceptor::unbind()
642                            {
643 kumpf            1.92          if (_rep)
644                                {
645                                    _portNumber = 0;
646 kumpf            1.116             _rep->closeSocket();
647 karl             1.91      
648 dave.sudlik      1.101             if (_connectionType == LOCAL_CONNECTION)
649 kumpf            1.92              {
650 karl             1.91      #ifndef PEGASUS_DISABLE_LOCAL_DOMAIN_SOCKET
651 kumpf            1.92                  ::unlink(
652                                            reinterpret_cast<struct sockaddr_un*>(_rep->address)->sun_path);
653 karl             1.91      #else
654 kumpf            1.92                  PEGASUS_ASSERT(false);
655 karl             1.91      #endif
656 kumpf            1.92              }
657 karl             1.91      
658 kumpf            1.92              delete _rep;
659                                    _rep = 0;
660                                }
661                                else
662                                {
663 mike             1.122.4.1         PEG_TRACE_CSTRING(TRC_HTTP, Tracer::LEVEL1,
664 kumpf            1.92                  "HTTPAcceptor::unbind failure _rep is null." );
665                                }
666 karl             1.91      }
667                            
668                            void HTTPAcceptor::destroyConnections()
669                            {
670 kumpf            1.92          if (_rep)
671                                {
672                                    // For each connection created by this object:
673 karl             1.91      
674 kumpf            1.92              AutoMutex autoMut(_rep->_connection_mut);
675                                    for (Uint32 i = 0, n = _rep->connections.size(); i < n; i++)
676                                    {
677                                        HTTPConnection* connection = _rep->connections[i];
678                                        SocketHandle socket = connection->getSocket();
679 karl             1.91      
680 kumpf            1.92                  // Unsolicit SocketMessages:
681 karl             1.91      
682 kumpf            1.92                  _monitor->unsolicitSocketMessages(socket);
683 karl             1.91      
684 kumpf            1.92                  // Destroy the connection (causing it to close):
685 karl             1.91      
686 kumpf            1.92                  while (connection->refcount.get()) { }
687                                        delete connection;
688                                    }
689 karl             1.91      
690 kumpf            1.92              _rep->connections.clear();
691                                }
692 karl             1.91      }
693                            
694                            void HTTPAcceptor::_acceptConnection()
695                            {
696 kumpf            1.92          // This function cannot be called on an invalid socket!
697 karl             1.91      
698 kumpf            1.92          PEGASUS_ASSERT(_rep != 0);
699 karl             1.91      
700 kumpf            1.92          // Accept the connection (populate the address):
701 karl             1.91      
702 kumpf            1.92          struct sockaddr* accept_address;
703                                SocketLength address_size;
704 karl             1.91      
705 dave.sudlik      1.101         if (_connectionType == LOCAL_CONNECTION)
706 kumpf            1.92          {
707 karl             1.91      #ifndef PEGASUS_DISABLE_LOCAL_DOMAIN_SOCKET
708 kumpf            1.92              accept_address =
709                                        reinterpret_cast<struct sockaddr*>(new struct sockaddr_un);
710                                    address_size = sizeof(struct sockaddr_un);
711 karl             1.91      #else
712 kumpf            1.92              PEGASUS_ASSERT(false);
713 karl             1.91      #endif
714 kumpf            1.92          }
715                                else
716                                {
717 dave.sudlik      1.101     #ifdef PEGASUS_ENABLE_IPV6
718                                    accept_address =
719                                       reinterpret_cast<struct sockaddr*>
720                                       (new struct sockaddr_storage);
721                                    address_size = sizeof(struct sockaddr_storage);
722                            #else
723 kumpf            1.92              accept_address =
724                                        reinterpret_cast<struct sockaddr*>(new struct sockaddr_in);
725                                    address_size = sizeof(struct sockaddr_in);
726 dave.sudlik      1.101     #endif
727 kumpf            1.92          }
728                            
729 kumpf            1.109         // It is not necessary to handle EINTR errors from this accept() call.
730                                // An EINTR error should not occur on a non-blocking socket.  If the
731                                // listen socket is blocking and EINTR occurs, the new socket connection
732                                // is not accepted here.
733                            
734                                // EAGAIN errors are also not handled here.  An EAGAIN error should not
735                                // occur after select() indicates that the listen socket is available for
736                                // reading.  If the accept() fails with an EAGAIN error code, a new
737                                // connection is not accepted here.
738                            
739                                SocketHandle socket = accept(_rep->socket, accept_address, &address_size);
740 kumpf            1.92      
741                                if (socket == PEGASUS_SOCKET_ERROR)
742                                {
743                                    // the remote connection is invalid, destroy client address.
744                                    delete accept_address;
745                            
746                                    // TCPIP is down reconnect this acceptor
747                                    if (getSocketError() == PEGASUS_NETWORK_TCPIP_STOPPED)
748                                    {
749 mike             1.122.4.1             PEG_TRACE_CSTRING(TRC_DISCARDED_DATA, Tracer::LEVEL1,
750 kumpf            1.92                      "Socket has an IO error. TCP/IP down. Try to reconnect.");
751                            
752                                        reconnectConnectionSocket();
753                            
754                                        return;
755                                    }
756 marek            1.119             PEG_TRACE((
757                                        TRC_DISCARDED_DATA,
758 marek            1.120                 Tracer::LEVEL1,
759 marek            1.119                 "HTTPAcceptor: accept() failed.  errno: %u",
760                                        errno));
761 kumpf            1.92              return;
762                                }
763 kumpf            1.116     
764                                // Use an AutoPtr to ensure the socket handle is closed on exception
765                                AutoPtr<SocketHandle, CloseSocketHandle> socketPtr(&socket);
766                            
767 marek            1.114     #ifndef PEGASUS_OS_TYPE_WINDOWS
768 marek            1.111         // We need to ensure that the socket number is not higher than
769                                // what fits into FD_SETSIZE, because we else won't be able to select on it
770                                // and won't ever communicate correct on that socket.
771                                if (socket >= FD_SETSIZE)
772                                {
773                                    // the remote connection is invalid, destroy client address.
774                                    delete accept_address;
775                            
776                                    PEG_TRACE(
777                                        (TRC_DISCARDED_DATA,
778 marek            1.120                  Tracer::LEVEL1,
779 marek            1.119                  "HTTPAcceptor out of available sockets." 
780                                             "accept() returned too large socket number %u."
781                                             "Closing connection to the new client.",
782 marek            1.111                  socket));
783                                    
784                                    return;
785                                }
786 marek            1.114     #endif
787 karl             1.91      
788 kumpf            1.92          String ipAddress;
789 karl             1.91      
790 dave.sudlik      1.101         if (_connectionType == LOCAL_CONNECTION)
791 kumpf            1.92          {
792                                    ipAddress = "localhost";
793                                }
794                                else
795                                {
796 dave.sudlik      1.101     #ifdef PEGASUS_ENABLE_IPV6
797                                    char ipBuffer[PEGASUS_INET6_ADDRSTR_LEN];
798 dmitry.mikulin   1.105             int rc;
799 dmitry.mikulin   1.106             if ((rc = System::getNameInfo(accept_address, 
800                                            address_size, 
801                                            ipBuffer,
802                                            PEGASUS_INET6_ADDRSTR_LEN, 
803                                            0, 
804                                            0, 
805                                            NI_NUMERICHOST)))
806 dave.sudlik      1.101             {
807 marek            1.119                 PEG_TRACE((
808                                            TRC_DISCARDED_DATA,
809 marek            1.120                     Tracer::LEVEL1,
810 marek            1.119                     "HTTPAcceptor: getnameinfo() failed.  rc: %d",
811                                            rc));
812 dave.sudlik      1.101                 delete accept_address;
813                                        return;
814                                    }
815                                    ipAddress = ipBuffer;
816                            #else
817 kumpf            1.92              unsigned char* sa = reinterpret_cast<unsigned char*>(
818                                        &reinterpret_cast<struct sockaddr_in*>(
819                                            accept_address)->sin_addr.s_addr);
820                                    char ipBuffer[32];
821                                    sprintf(ipBuffer, "%u.%u.%u.%u", sa[0], sa[1], sa[2], sa[3]);
822                                    ipAddress = ipBuffer;
823 dave.sudlik      1.101     #endif
824 kumpf            1.92          }
825 karl             1.91      
826 kumpf            1.92          delete accept_address;
827 karl             1.91      
828                            // set the close on exec flag
829                            #if !defined(PEGASUS_OS_TYPE_WINDOWS) && !defined(PEGASUS_OS_VMS)
830 kumpf            1.92          int sock_flags;
831                                if ((sock_flags = fcntl(socket, F_GETFD, 0)) < 0)
832                                {
833 mike             1.122.4.1         PEG_TRACE_CSTRING(TRC_DISCARDED_DATA, Tracer::LEVEL1,
834 kumpf            1.92                  "HTTPAcceptor: fcntl(F_GETFD) failed");
835                                }
836                                else
837                                {
838                                    sock_flags |= FD_CLOEXEC;
839                                    if (fcntl(socket, F_SETFD, sock_flags) < 0)
840                                    {
841 mike             1.122.4.1             PEG_TRACE_CSTRING(TRC_DISCARDED_DATA, Tracer::LEVEL1,
842 kumpf            1.92                      "HTTPAcceptor: fcntl(F_SETFD) failed");
843                                    }
844                                }
845 karl             1.91      #endif
846                            
847                            
848 r.kieninger      1.122         PEG_TRACE((
849                                    TRC_HTTP,
850                                    Tracer::LEVEL3,
851                                    "HTTPAcceptor - accept() success.  Socket: %u",
852                                    socket));
853 kumpf            1.92      
854 kumpf            1.96          SharedPtr<MP_Socket> mp_socket(new MP_Socket(
855 sushma.fernandes 1.97              socket, _sslcontext, _sslContextObjectLock, ipAddress));
856 kumpf            1.116         // mp_socket now has responsibility for closing the socket handle
857                                socketPtr.release();
858 kumpf            1.92      
859 kumpf            1.109         mp_socket->disableBlocking();
860 kumpf            1.92          mp_socket->setSocketWriteTimeout(_socketWriteTimeout);
861                            
862 kumpf            1.109         // Perform the SSL handshake, if applicable.
863 kumpf            1.92      
864                                Sint32 socketAcceptStatus = mp_socket->accept();
865                            
866                                if (socketAcceptStatus < 0)
867                                {
868 mike             1.122.4.1         PEG_TRACE_CSTRING(TRC_DISCARDED_DATA, Tracer::LEVEL1,
869 kumpf            1.92                  "HTTPAcceptor: SSL_accept() failed");
870                                    return;
871                                }
872                            
873                                // Create a new connection and add it to the connection list:
874                            
875 kumpf            1.116         AutoPtr<HTTPConnection> connection(new HTTPConnection(
876                                    _monitor,
877                                    mp_socket,
878                                    ipAddress,
879                                    this,
880 mike             1.122.4.1         _outputMessageQueue));
881 kumpf            1.92      
882 dave.sudlik      1.108         if (_idleConnectionTimeoutSeconds)
883                                {
884                                    connection->_idleConnectionTimeoutSeconds = 
885                                        _idleConnectionTimeoutSeconds;
886                                    Time::gettimeofday(&connection->_idleStartTime);
887                                }
888                            
889 kumpf            1.92          if (socketAcceptStatus == 0)
890                                {
891 mike             1.122.4.1         PEG_TRACE_CSTRING(TRC_HTTP, Tracer::LEVEL1,
892 kumpf            1.92                  "HTTPAcceptor: SSL_accept() pending");
893                                    connection->_acceptPending = true;
894 dave.sudlik      1.108             Time::gettimeofday(&connection->_acceptPendingStartTime);
895 kumpf            1.92          }
896 karl             1.91      
897 kumpf            1.92          // Solicit events on this new connection's socket:
898                                int index;
899 karl             1.91      
900 kumpf            1.92          if (-1 ==  (index = _monitor->solicitSocketMessages(
901                                        connection->getSocket(),
902                                        SocketMessage::READ | SocketMessage::EXCEPTION,
903 kumpf            1.107                 connection->getQueueId(), MonitorEntry::TYPE_CONNECTION)) )
904 kumpf            1.92          {
905 mike             1.122.4.1         PEG_TRACE_CSTRING(TRC_DISCARDED_DATA, Tracer::LEVEL1,
906 kumpf            1.92                  "HTTPAcceptor::_acceptConnection: Attempt to allocate entry in "
907                                            "_entries table failed.");
908                                    return;
909                                }
910 karl             1.91      
911 kumpf            1.92          connection->_entry_index = index;
912                                AutoMutex autoMut(_rep->_connection_mut);
913 kumpf            1.116         _rep->connections.append(connection.get());
914                                connection.release();
915 karl             1.91      }
916                            
917 kumpf            1.92      PEGASUS_NAMESPACE_END

No CVS admin address has been configured
Powered by
ViewCVS 0.9.2