(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                                PEG_TRACE_STRING(TRC_DISCARDED_DATA, Tracer::LEVEL2,
292                                    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 marek            1.95          PEG_TRACE_CSTRING(TRC_DISCARDED_DATA, Tracer::LEVEL2,
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 marek            1.95              PEG_TRACE_CSTRING(TRC_DISCARDED_DATA, Tracer::LEVEL2,
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 marek            1.95              PEG_TRACE_CSTRING(TRC_HTTP, Tracer::LEVEL2,
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 marek            1.95          PEG_TRACE_CSTRING(TRC_DISCARDED_DATA, Tracer::LEVEL2,
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 marek            1.95              PEG_TRACE_CSTRING(TRC_HTTP, Tracer::LEVEL2,
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 marek            1.95          PEG_TRACE_CSTRING(TRC_DISCARDED_DATA, Tracer::LEVEL2,
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 sushma.fernandes 1.117         PEG_TRACE_CSTRING(TRC_HTTP, Tracer::LEVEL2,
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 marek            1.95              PEG_TRACE_CSTRING(TRC_DISCARDED_DATA, Tracer::LEVEL2,
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 marek            1.95          PEG_TRACE_CSTRING(TRC_DISCARDED_DATA, Tracer::LEVEL2,
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 marek            1.95              PEG_TRACE_CSTRING(TRC_DISCARDED_DATA, Tracer::LEVEL2,
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 marek            1.95          PEG_TRACE_CSTRING(TRC_DISCARDED_DATA, Tracer::LEVEL2,
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                                static_cast<MessageQueue *>(_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 marek            1.95          PEG_TRACE_CSTRING(TRC_HTTP, Tracer::LEVEL2,
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 marek            1.95          PEG_TRACE_CSTRING(TRC_DISCARDED_DATA, Tracer::LEVEL2,
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