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

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

No CVS admin address has been configured
Powered by
ViewCVS 0.9.2