(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 dev.meetei   1.132                            ReadWriteSem* sslContextObjectLock,
138                                               HostAddress *listenOn)
139 karl         1.91     : Base(PEGASUS_QUEUENAME_HTTPACCEPTOR),  // ATTN: Need unique names?
140                         _monitor(monitor),
141                         _outputMessageQueue(outputMessageQueue),
142                         _rep(0),
143                         _entry_index(-1),
144 dave.sudlik  1.101      _connectionType(connectionType),
145 karl         1.91       _portNumber(portNumber),
146                         _sslcontext(sslcontext),
147 dev.meetei   1.132     _sslContextObjectLock(sslContextObjectLock),
148                        _listenAddress(listenOn)
149 karl         1.91  {
150 ouyang.jian  1.121    PEGASUS_ASSERT(!_sslcontext == !_sslContextObjectLock);
151 karl         1.91     Socket::initializeInterface();
152                    
153                       /*
154 mateus.baur  1.103         Platforms interpret the value of _maxConnectionQueueLength
155 kumpf        1.92          differently.  Some platforms interpret the value literally, while
156                            others multiply a fudge factor. When the server is under stress from
157                            multiple clients with multiple requests, toggling this number may
158                            prevent clients from being dropped.  Instead of hard coding the
159                            value, we allow an environment variable to be set which specifies a
160                            number greater than the maximum concurrent client connections
161                            possible.  If this environment var is not specified, then
162 mateus.baur  1.103         _maxConnectionQueueLength = 15.
163 karl         1.91     */
164                    
165 kumpf        1.92  //To engage runtime backlog queue length: uncomment the following block AND
166 mateus.baur  1.103 //comment out the line _maxConnectionQueueLength = 15
167 karl         1.91  
168                    /*
169 mateus.baur  1.103     if (_maxConnectionQueueLength == -1)
170 kumpf        1.92      {
171                            const char* env = getenv("PEGASUS_MAX_BACKLOG_CONNECTION_QUEUE");
172                            if (!env)
173                            {
174 mateus.baur  1.103             _maxConnectionQueueLength = 15;
175 kumpf        1.92          }
176                            else
177                            {
178                                char* end = NULL;
179 mateus.baur  1.103             _maxConnectionQueueLength = strtol(env, &end, 10);
180 kumpf        1.92              if (*end)
181 mateus.baur  1.103                 _maxConnectionQueueLength = 15;
182                                cout << " _maxConnectionQueueLength = " <<
183                                    _maxConnectionQueueLength << endl;
184 kumpf        1.92          }
185 karl         1.91      }
186                    */
187 mateus.baur  1.103 #ifdef PEGASUS_WMIMAPPER
188                        //The WMI Mapper can be used as a proxy to multiple WMI Servers.
189                        //If a client application simultaneously initiates connections
190                        //to many Windows systems, many of these connections may be routed
191                        //to a single WMI Mapper. A larger _maxConnectionQueueLength
192                        //value is required to allow these connections to be initiated
193                        //successfully.
194                        _maxConnectionQueueLength = 40;
195                    #else
196                        _maxConnectionQueueLength = 15;
197                    #endif
198 karl         1.91  }
199                    
200                    HTTPAcceptor::~HTTPAcceptor()
201                    {
202 kumpf        1.92      destroyConnections();
203                        unbind();
204                        // ATTN: Is this correct in a multi-HTTPAcceptor server?
205                        Socket::uninitializeInterface();
206 karl         1.91  }
207                    
208                    void HTTPAcceptor::handleEnqueue(Message *message)
209                    {
210 kumpf        1.92      if (!message)
211                           return;
212                    
213                        PEGASUS_ASSERT(_rep != 0);
214                        switch (message->getType())
215                        {
216                            case SOCKET_MESSAGE:
217                            {
218                                SocketMessage* socketMessage = (SocketMessage*)message;
219                    
220                                // If this is a connection request:
221 sushma.fernandes 1.117             PEGASUS_ASSERT(socketMessage->socket == _rep->socket);
222 kumpf            1.92  
223 sushma.fernandes 1.117             PEGASUS_ASSERT(socketMessage->events & SocketMessage::READ);
224                        
225                                    _acceptConnection();
226 karl             1.91  
227 sushma.fernandes 1.117             break;
228                                }
229 kumpf            1.92  
230                               case CLOSE_CONNECTION_MESSAGE:
231                               {
232                                   CloseConnectionMessage* closeConnectionMessage =
233                                       (CloseConnectionMessage*)message;
234                        
235                                   AutoMutex autoMut(_rep->_connection_mut);
236                        
237                                   for (Uint32 i = 0, n = _rep->connections.size(); i < n; i++)
238                                   {
239                                       HTTPConnection* connection = _rep->connections[i];
240                                       SocketHandle socket = connection->getSocket();
241                        
242                                       if (socket == closeConnectionMessage->socket)
243                                       {
244                                           _monitor->unsolicitSocketMessages(socket);
245                                           _rep->connections.remove(i);
246                                           delete connection;
247                                           break;
248                                       }
249                                   }
250 karl             1.91  
251 kumpf            1.92             break;
252                               }
253 karl             1.91  
254 kumpf            1.92         default:
255 sushma.fernandes 1.117            PEGASUS_ASSERT(false);
256 kumpf            1.92             break;
257                            }
258 karl             1.91  
259 kumpf            1.92      delete message;
260 karl             1.91  }
261                        
262                        
263                        void HTTPAcceptor::handleEnqueue()
264                        {
265 kumpf            1.92      Message* message = dequeue();
266                            handleEnqueue(message);
267 karl             1.91  }
268                        
269                        void HTTPAcceptor::bind()
270                        {
271 kumpf            1.92      if (_rep)
272                            {
273                                MessageLoaderParms parms("Common.HTTPAcceptor.ALREADY_BOUND",
274                                    "HTTPAcceptor already bound");
275                                throw BindFailedException(parms);
276                            }
277 karl             1.91  
278 dave.sudlik      1.101     _rep = new HTTPAcceptorRep(_connectionType);
279 karl             1.91  
280 kumpf            1.92      // bind address
281                            _bind();
282 karl             1.91  }
283                        
284 dev.meetei       1.132 
285 karl             1.91  /**
286 kumpf            1.92      _bind - creates a new server socket and bind socket to the port address.
287                            If PEGASUS_DISABLE_LOCAL_DOMAIN_SOCKET is not defined, the port number is
288                            ignored and a domain socket is bound.
289 karl             1.91  */
290                        void HTTPAcceptor::_bind()
291                        {
292 ouyang.jian      1.102 #ifdef PEGASUS_OS_PASE
293 ouyang.jian      1.127     AutoPtr<PaseCcsid> ccsid;
294 ouyang.jian      1.102 #endif
295                        
296 kumpf            1.92      PEGASUS_ASSERT(_rep != 0);
297                            // Create address:
298 dave.sudlik      1.101     memset(_rep->address, 0, _rep->address_size);
299 karl             1.91  
300 dave.sudlik      1.101     if (_connectionType == LOCAL_CONNECTION)
301 kumpf            1.92      {
302 karl             1.91  #ifndef PEGASUS_DISABLE_LOCAL_DOMAIN_SOCKET
303 kumpf            1.100         //
304                                // Make sure the local domain socket can be owned by the cimserver
305                                // user.  Otherwise, the bind may fail with a vague "bind failed"
306                                // error.
307                                //
308 ouyang.jian      1.127 #ifdef PEGASUS_OS_PASE
309                                // PASE domain socket needs ccsid 819
310                                int orig_ccsid;
311                                orig_ccsid = _SETCCSID(-1);
312                                if (orig_ccsid == -1)
313                                {
314                                    PEG_TRACE_CSTRING(TRC_DISCARDED_DATA, Tracer::LEVEL1,
315                                            "HTTPAcceptor::_bind: Can not get current PASE CCSID.");
316                                    orig_ccsid = 1208;
317                                }
318                                ccsid.reset(new PaseCcsid(819, orig_ccsid));
319                        #endif
320 kumpf            1.100         if (System::exists(PEGASUS_LOCAL_DOMAIN_SOCKET_PATH))
321                                {
322                                    if (!System::removeFile(PEGASUS_LOCAL_DOMAIN_SOCKET_PATH))
323                                    {
324                                        throw CannotRemoveFile(PEGASUS_LOCAL_DOMAIN_SOCKET_PATH);
325                                    }
326                                }
327                        
328 kumpf            1.92          reinterpret_cast<struct sockaddr_un*>(_rep->address)->sun_family =
329                                    AF_UNIX;
330                                strcpy(reinterpret_cast<struct sockaddr_un*>(_rep->address)->sun_path,
331                                    PEGASUS_LOCAL_DOMAIN_SOCKET_PATH);
332 karl             1.91  #else
333 kumpf            1.92          PEGASUS_ASSERT(false);
334 karl             1.91  #endif
335 kumpf            1.92      }
336 dave.sudlik      1.101 #ifdef PEGASUS_ENABLE_IPV6
337                            else if (_connectionType == IPV6_CONNECTION)
338                            {
339 dev.meetei       1.132         if(_listenAddress)
340                                {
341                                    String hostAdd = _listenAddress->getHost();
342                                    CString ip = hostAdd.getCString();
343                        
344                                    struct sockaddr_in6 in6addr;
345                                    memset(&in6addr, 0, sizeof(sockaddr_in6));
346                                    if(_listenAddress ->isHostAddLinkLocal())
347                                    {
348 ashok.pathak     1.133                 HostAddress::convertTextToBinary(AF_INET6, 
349 dev.meetei       1.132                 (const char*)ip,
350                                        &in6addr.sin6_addr);
351                                        reinterpret_cast<struct sockaddr_in6*>(
352                                            _rep->address)->sin6_addr = in6addr.sin6_addr;
353                                        reinterpret_cast<struct sockaddr_in6*>(
354                                            _rep->address)->sin6_scope_id = 
355                                                _listenAddress->getScopeID();
356                                    }
357                                    else
358                                    {
359 ashok.pathak     1.133                 HostAddress::convertTextToBinary(AF_INET6, 
360 dev.meetei       1.132                 (const char*)ip,
361                                        &in6addr.sin6_addr);
362                                        reinterpret_cast<struct sockaddr_in6*>(
363                                            _rep->address)->sin6_addr = in6addr.sin6_addr;
364                                    }
365                                }
366                                else
367                                {
368 dave.sudlik      1.101         reinterpret_cast<struct sockaddr_in6*>(_rep->address)->sin6_addr =
369                                    in6addr_any;
370 dev.meetei       1.132         }
371 dave.sudlik      1.101         reinterpret_cast<struct sockaddr_in6*>(_rep->address)->sin6_family =
372                                    AF_INET6;
373                                reinterpret_cast<struct sockaddr_in6*>(_rep->address)->sin6_port =
374                                    htons(_portNumber);
375                            }
376                        #endif
377                            else if(_connectionType == IPV4_CONNECTION)
378 kumpf            1.92      {
379 dev.meetei       1.132         if(_listenAddress)
380                                {
381                                    String hostAdd = _listenAddress->getHost();
382                                    CString ip = hostAdd.getCString();
383                                    struct sockaddr_in addrs;
384 ashok.pathak     1.133             HostAddress::convertTextToBinary(
385 dev.meetei       1.132                 AF_INET, 
386                                        (const char*)ip,
387                                        &addrs.sin_addr);
388                                    reinterpret_cast<struct sockaddr_in*>(
389                                        _rep->address)->sin_addr.s_addr = addrs.sin_addr.s_addr;
390                                }
391                                else
392                                {
393                                    reinterpret_cast<struct sockaddr_in*>(
394                                    _rep->address)->sin_addr.s_addr = INADDR_ANY;
395                                }
396 kumpf            1.92          reinterpret_cast<struct sockaddr_in*>(_rep->address)->sin_family =
397                                    AF_INET;
398                                reinterpret_cast<struct sockaddr_in*>(_rep->address)->sin_port =
399                                    htons(_portNumber);
400                            }
401 dave.sudlik      1.101     else
402                            {
403                                PEGASUS_ASSERT(false);
404                            }
405 kumpf            1.92  
406                            // Create socket:
407                        
408 dave.sudlik      1.101     if (_connectionType == LOCAL_CONNECTION)
409 kumpf            1.92      {
410                                _rep->socket = Socket::createSocket(AF_UNIX, SOCK_STREAM, 0);
411                            }
412 dave.sudlik      1.101 #ifdef PEGASUS_ENABLE_IPV6
413                            else if (_connectionType == IPV6_CONNECTION)
414                            {
415                                _rep->socket = Socket::createSocket(PF_INET6, SOCK_STREAM, IPPROTO_TCP);
416                            }
417                        #endif
418                            else if (_connectionType == IPV4_CONNECTION)
419                            {
420                                _rep->socket = Socket::createSocket(PF_INET, SOCK_STREAM, IPPROTO_TCP);
421                            }
422 kumpf            1.92      else
423                            {
424 dave.sudlik      1.101         PEGASUS_ASSERT(false);
425 kumpf            1.92      }
426                        
427                            if (_rep->socket < 0)
428                            {
429                                delete _rep;
430                                _rep = 0;
431                                MessageLoaderParms parms("Common.HTTPAcceptor.FAILED_CREATE_SOCKET",
432                                    "Failed to create socket");
433                                throw BindFailedException(parms);
434                            }
435 karl             1.91  
436 kumpf            1.109     Socket::disableBlocking(_rep->socket);
437 karl             1.91  
438                        // set the close-on-exec bit for this file handle.
439                        // any unix that forks needs this bit set.
440                        #if !defined PEGASUS_OS_TYPE_WINDOWS && !defined(PEGASUS_OS_VMS)
441 kumpf            1.92      int sock_flags;
442                            if ((sock_flags = fcntl(_rep->socket, F_GETFD, 0)) < 0)
443                            {
444 marek            1.124         PEG_TRACE_CSTRING(TRC_DISCARDED_DATA, Tracer::LEVEL1,
445 kumpf            1.92              "HTTPAcceptor::_bind: fcntl(F_GETFD) failed");
446                            }
447                            else
448                            {
449                                sock_flags |= FD_CLOEXEC;
450                                if (fcntl(_rep->socket, F_SETFD, sock_flags) < 0)
451                                {
452 marek            1.124             PEG_TRACE_CSTRING(TRC_DISCARDED_DATA, Tracer::LEVEL1,
453 kumpf            1.92                  "HTTPAcceptor::_bind: fcntl(F_SETFD) failed");
454                                }
455                            }
456                        #endif
457                        
458                        
459                            //
460                            // Set the socket option SO_REUSEADDR to reuse the socket address so
461                            // that we can rebind to a new socket using the same address when we
462                            // need to resume the cimom as a result of a timeout during a Shutdown
463                            // operation.
464                            //
465                            int opt=1;
466                            if (setsockopt(_rep->socket, SOL_SOCKET, SO_REUSEADDR,
467                                    (char *)&opt, sizeof(opt)) < 0)
468                            {
469                                delete _rep;
470                                _rep = 0;
471                                MessageLoaderParms parms("Common.HTTPAcceptor.FAILED_SET_SOCKET_OPTION",
472                                    "Failed to set socket option");
473                                throw BindFailedException(parms);
474 kumpf            1.92      }
475                        
476                        
477                            //
478                            // Bind socket to port:
479                            //
480                            if (::bind(_rep->socket, _rep->address, _rep->address_size) < 0)
481                            {
482 thilo.boehm      1.115         MessageLoaderParms parms(
483                                    "Common.HTTPAcceptor.FAILED_BIND_SOCKET_DETAIL",
484                                    "Failed to bind socket on port $0: $1.",
485                                    _portNumber, PEGASUS_SYSTEM_NETWORK_ERRORMSG_NLS);
486                        
487 kumpf            1.92          delete _rep;
488                                _rep = 0;
489                                throw BindFailedException(parms);
490                            }
491                        
492                        
493                            //
494                            // Get the actual port value used if the caller specified a port value of 0.
495                            //
496                            if (_portNumber == 0)
497                            {
498                                sockaddr_in buf;
499                                SocketLength bufSize = sizeof(buf);
500                                if (getsockname(_rep->socket, reinterpret_cast<sockaddr *>(&buf),
501                                        &bufSize) == 0 )
502                                {
503                                    _portNumber = ntohs(buf.sin_port);
504                                }
505                            }
506                        
507                        
508 kumpf            1.92      //
509                            // Change permissions on Linux local domain socket to allow writes by
510                            // others.
511                            //
512 karl             1.91  #if !defined(PEGASUS_DISABLE_LOCAL_DOMAIN_SOCKET) && \
513 kumpf            1.92       (defined(PEGASUS_PLATFORM_LINUX_GENERIC_GNU) || \
514 r.kieninger      1.126       defined(PEGASUS_OS_ZOS) || \
515 ouyang.jian      1.118       defined(PEGASUS_OS_PASE))
516 dave.sudlik      1.101     if (_connectionType == LOCAL_CONNECTION)
517 kumpf            1.92      {
518                                if (::chmod(PEGASUS_LOCAL_DOMAIN_SOCKET_PATH,
519                                        S_IRUSR | S_IWUSR | S_IXUSR |
520                                        S_IRGRP | S_IWGRP | S_IXGRP |
521                                        S_IROTH | S_IWOTH | S_IXOTH ) < 0 )
522                                {
523 thilo.boehm      1.115             MessageLoaderParms parms(
524                                        "Common.HTTPAcceptor.FAILED_SET_LDS_FILE_OPTION",
525 dev.meetei       1.132                 "Failed to set permission on local domain socket $0: $1.",
526 thilo.boehm      1.115                 PEGASUS_LOCAL_DOMAIN_SOCKET_PATH,
527                                        PEGASUS_SYSTEM_ERRORMSG_NLS );
528                        
529 kumpf            1.92              delete _rep;
530                                    _rep = 0;
531                                    throw BindFailedException(parms);
532                                }
533                            }
534                        #endif
535                        
536                            // Set up listening on the given socket:
537                        
538 mateus.baur      1.103     //int const _maxConnectionQueueLength = 15;
539 kumpf            1.92  
540 thilo.boehm      1.115     if (::listen(_rep->socket, _maxConnectionQueueLength) < 0)
541 kumpf            1.92      {
542 thilo.boehm      1.115         MessageLoaderParms parms(
543                                    "Common.HTTPAcceptor.FAILED_LISTEN_SOCKET",
544 dev.meetei       1.132             "Failed to listen on socket $0: $1.",
545 thilo.boehm      1.115             (int)_rep->socket,PEGASUS_SYSTEM_NETWORK_ERRORMSG_NLS );
546 kumpf            1.131 
547 kumpf            1.92          delete _rep;
548                                _rep = 0;
549                                throw BindFailedException(parms);
550                            }
551                        
552                            // Register to receive SocketMessages on this socket:
553                        
554                            if (-1 == ( _entry_index = _monitor->solicitSocketMessages(
555                                    _rep->socket,
556                                    SocketMessage::READ | SocketMessage::EXCEPTION,
557                                    getQueueId(),
558 kumpf            1.107             MonitorEntry::TYPE_ACCEPTOR)))
559 kumpf            1.92      {
560                                delete _rep;
561                                _rep = 0;
562                                MessageLoaderParms parms(
563                                    "Common.HTTPAcceptor.FAILED_SOLICIT_SOCKET_MESSAGES",
564                                    "Failed to solicit socket messaeges");
565                                throw BindFailedException(parms);
566                            }
567 karl             1.91  }
568                        
569                        /**
570 kumpf            1.92      closeConnectionSocket - close the server listening socket to disallow
571                            new client connections.
572 karl             1.91  */
573                        void HTTPAcceptor::closeConnectionSocket()
574                        {
575 kumpf            1.92      if (_rep)
576                            {
577                                // unregister the socket
578                        
579                                // ATTN - comment out - see CIMServer::stopClientConnection()
580                                //_monitor->unsolicitSocketMessages(_rep->socket);
581                        
582                                // close the socket
583 kumpf            1.116         _rep->closeSocket();
584 kumpf            1.92          // Unlink Local Domain Socket Bug# 3312
585 dave.sudlik      1.101         if (_connectionType == LOCAL_CONNECTION)
586 kumpf            1.92          {
587 karl             1.91  #ifndef PEGASUS_DISABLE_LOCAL_DOMAIN_SOCKET
588 marek            1.124             PEG_TRACE_CSTRING(TRC_HTTP, Tracer::LEVEL3,
589 kumpf            1.92                  "HTTPAcceptor::closeConnectionSocket Unlinking local "
590                                            "connection.");
591                                    ::unlink(
592 dev.meetei       1.132                     reinterpret_cast<struct sockaddr_un*>
593                                                (_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                            }
599                            else
600                            {
601 sushma.fernandes 1.117         PEG_TRACE_CSTRING(TRC_HTTP, Tracer::LEVEL2,
602 kumpf            1.92              "HTTPAcceptor::closeConnectionSocket failure _rep is null.");
603                            }
604 karl             1.91  }
605                        
606                        /**
607                           reopenConnectionSocket - creates a new server socket.
608                        */
609                        void HTTPAcceptor::reopenConnectionSocket()
610                        {
611 kumpf            1.92      if (_rep)
612                            {
613                                _bind();
614                            }
615                            else
616                            {
617 marek            1.124         PEG_TRACE_CSTRING(TRC_DISCARDED_DATA, Tracer::LEVEL1,
618 kumpf            1.92              "HTTPAcceptor::reopenConnectionSocket failure _rep is null.");
619                            }
620 karl             1.91  }
621                        
622                        
623                        /**
624                           reconnectConnectionSocket - creates a new server socket.
625                        */
626                        void HTTPAcceptor::reconnectConnectionSocket()
627                        {
628 kumpf            1.92      if (_rep)
629                            {
630                                // unregister the socket
631                                _monitor->unsolicitSocketMessages(_rep->socket);
632                                // close the socket
633 kumpf            1.116         _rep->closeSocket();
634                                // Unlink Local Domain Socket
635 dave.sudlik      1.101         if (_connectionType == LOCAL_CONNECTION)
636 kumpf            1.92          {
637 karl             1.91  #ifndef PEGASUS_DISABLE_LOCAL_DOMAIN_SOCKET
638 marek            1.124             PEG_TRACE_CSTRING(TRC_HTTP, Tracer::LEVEL3,
639 kumpf            1.92                  "HTTPAcceptor::reconnectConnectionSocket Unlinking local "
640                                            "connection." );
641                                    ::unlink(
642 dev.meetei       1.132                     reinterpret_cast<struct sockaddr_un*>(
643                                                _rep->address)->sun_path);
644 karl             1.91  #else
645 kumpf            1.92              PEGASUS_ASSERT(false);
646 karl             1.91  #endif
647 kumpf            1.92          }
648                                // open the socket
649                                _bind();
650                            }
651                            else
652                            {
653 marek            1.124         PEG_TRACE_CSTRING(TRC_DISCARDED_DATA, Tracer::LEVEL1,
654 kumpf            1.92              "HTTPAcceptor::reconnectConnectionSocket failure _rep is null.");
655                            }
656 karl             1.91  }
657                        
658                        /**
659 kumpf            1.92      getOutstandingRequestCount - returns the number of outstanding requests.
660 karl             1.91  */
661                        Uint32 HTTPAcceptor::getOutstandingRequestCount() const
662                        {
663 kumpf            1.92      Uint32 count = 0;
664                            if (_rep)
665                            {
666                                AutoMutex autoMut(_rep->_connection_mut);
667 kumpf            1.110         for (Uint32 i = 0, n = _rep->connections.size(); i < n; i++)
668 kumpf            1.92          {
669 kumpf            1.110             HTTPConnection* connection = _rep->connections[i];
670                                    if (connection->isResponsePending())
671                                    {
672                                        count++;
673                                    }
674 kumpf            1.92          }
675                            }
676                            return count;
677 karl             1.91  }
678                        
679                        
680                        /**
681                            getPortNumber - returns the port number used for the connection
682                        */
683                        Uint32 HTTPAcceptor::getPortNumber() const
684                        {
685                            return _portNumber;
686                        }
687                        
688                        void HTTPAcceptor::setSocketWriteTimeout(Uint32 socketWriteTimeout)
689                        {
690 kavita.gupta     1.128 #ifndef PEGASUS_INTEGERS_BOUNDARY_ALIGNED
691                            AutoMutex lock(_socketWriteTimeoutMutex);
692                        #endif
693 karl             1.91      _socketWriteTimeout = socketWriteTimeout;
694                        }
695                        
696                        void HTTPAcceptor::unbind()
697                        {
698 kumpf            1.92      if (_rep)
699                            {
700                                _portNumber = 0;
701 kumpf            1.116         _rep->closeSocket();
702 karl             1.91  
703 dave.sudlik      1.101         if (_connectionType == LOCAL_CONNECTION)
704 kumpf            1.92          {
705 karl             1.91  #ifndef PEGASUS_DISABLE_LOCAL_DOMAIN_SOCKET
706 kumpf            1.92              ::unlink(
707 dev.meetei       1.132                     reinterpret_cast<struct sockaddr_un*>
708                                            (_rep->address)->sun_path);
709 karl             1.91  #else
710 kumpf            1.92              PEGASUS_ASSERT(false);
711 karl             1.91  #endif
712 kumpf            1.92          }
713 karl             1.91  
714 kumpf            1.92          delete _rep;
715                                _rep = 0;
716                            }
717                            else
718                            {
719 marek            1.124         PEG_TRACE_CSTRING(TRC_HTTP, Tracer::LEVEL1,
720 kumpf            1.92              "HTTPAcceptor::unbind failure _rep is null." );
721                            }
722 karl             1.91  }
723                        
724                        void HTTPAcceptor::destroyConnections()
725                        {
726 kumpf            1.92      if (_rep)
727                            {
728                                // For each connection created by this object:
729 karl             1.91  
730 kumpf            1.92          AutoMutex autoMut(_rep->_connection_mut);
731                                for (Uint32 i = 0, n = _rep->connections.size(); i < n; i++)
732                                {
733                                    HTTPConnection* connection = _rep->connections[i];
734                                    SocketHandle socket = connection->getSocket();
735 karl             1.91  
736 kumpf            1.92              // Unsolicit SocketMessages:
737 karl             1.91  
738 kumpf            1.92              _monitor->unsolicitSocketMessages(socket);
739 karl             1.91  
740 kumpf            1.92              // Destroy the connection (causing it to close):
741 karl             1.91  
742 kumpf            1.92              while (connection->refcount.get()) { }
743                                    delete connection;
744                                }
745 karl             1.91  
746 kumpf            1.92          _rep->connections.clear();
747                            }
748 karl             1.91  }
749                        
750                        void HTTPAcceptor::_acceptConnection()
751                        {
752 kumpf            1.92      // This function cannot be called on an invalid socket!
753 karl             1.91  
754 kumpf            1.92      PEGASUS_ASSERT(_rep != 0);
755 karl             1.91  
756 kumpf            1.92      // Accept the connection (populate the address):
757 karl             1.91  
758 kumpf            1.92      struct sockaddr* accept_address;
759                            SocketLength address_size;
760 karl             1.91  
761 dave.sudlik      1.101     if (_connectionType == LOCAL_CONNECTION)
762 kumpf            1.92      {
763 karl             1.91  #ifndef PEGASUS_DISABLE_LOCAL_DOMAIN_SOCKET
764 kumpf            1.92          accept_address =
765                                    reinterpret_cast<struct sockaddr*>(new struct sockaddr_un);
766                                address_size = sizeof(struct sockaddr_un);
767 karl             1.91  #else
768 kumpf            1.92          PEGASUS_ASSERT(false);
769 karl             1.91  #endif
770 kumpf            1.92      }
771                            else
772                            {
773 dave.sudlik      1.101 #ifdef PEGASUS_ENABLE_IPV6
774                                accept_address =
775                                   reinterpret_cast<struct sockaddr*>
776                                   (new struct sockaddr_storage);
777                                address_size = sizeof(struct sockaddr_storage);
778                        #else
779 kumpf            1.92          accept_address =
780                                    reinterpret_cast<struct sockaddr*>(new struct sockaddr_in);
781                                address_size = sizeof(struct sockaddr_in);
782 dave.sudlik      1.101 #endif
783 kumpf            1.92      }
784                        
785 kumpf            1.109     // It is not necessary to handle EINTR errors from this accept() call.
786                            // An EINTR error should not occur on a non-blocking socket.  If the
787                            // listen socket is blocking and EINTR occurs, the new socket connection
788                            // is not accepted here.
789                        
790                            // EAGAIN errors are also not handled here.  An EAGAIN error should not
791                            // occur after select() indicates that the listen socket is available for
792                            // reading.  If the accept() fails with an EAGAIN error code, a new
793                            // connection is not accepted here.
794                        
795                            SocketHandle socket = accept(_rep->socket, accept_address, &address_size);
796 kumpf            1.92  
797                            if (socket == PEGASUS_SOCKET_ERROR)
798                            {
799                                // the remote connection is invalid, destroy client address.
800                                delete accept_address;
801                        
802                                // TCPIP is down reconnect this acceptor
803                                if (getSocketError() == PEGASUS_NETWORK_TCPIP_STOPPED)
804                                {
805 marek            1.124             PEG_TRACE_CSTRING(TRC_DISCARDED_DATA, Tracer::LEVEL1,
806 kumpf            1.92                  "Socket has an IO error. TCP/IP down. Try to reconnect.");
807                        
808                                    reconnectConnectionSocket();
809                        
810                                    return;
811                                }
812 marek            1.119         PEG_TRACE((
813                                    TRC_DISCARDED_DATA,
814 marek            1.120             Tracer::LEVEL1,
815 marek            1.119             "HTTPAcceptor: accept() failed.  errno: %u",
816                                    errno));
817 kumpf            1.92          return;
818                            }
819 kumpf            1.116 
820                            // Use an AutoPtr to ensure the socket handle is closed on exception
821                            AutoPtr<SocketHandle, CloseSocketHandle> socketPtr(&socket);
822                        
823 marek            1.114 #ifndef PEGASUS_OS_TYPE_WINDOWS
824 marek            1.111     // We need to ensure that the socket number is not higher than
825                            // what fits into FD_SETSIZE, because we else won't be able to select on it
826                            // and won't ever communicate correct on that socket.
827                            if (socket >= FD_SETSIZE)
828                            {
829                                // the remote connection is invalid, destroy client address.
830                                delete accept_address;
831                        
832                                PEG_TRACE(
833                                    (TRC_DISCARDED_DATA,
834 marek            1.120              Tracer::LEVEL1,
835 kumpf            1.131              "HTTPAcceptor out of available sockets."
836 marek            1.119                  "accept() returned too large socket number %u."
837                                         "Closing connection to the new client.",
838 marek            1.111              socket));
839 kumpf            1.131 
840 marek            1.111         return;
841                            }
842 marek            1.114 #endif
843 karl             1.91  
844 kumpf            1.92      String ipAddress;
845 karl             1.91  
846 dave.sudlik      1.101     if (_connectionType == LOCAL_CONNECTION)
847 kumpf            1.92      {
848                                ipAddress = "localhost";
849                            }
850                            else
851                            {
852 dave.sudlik      1.101 #ifdef PEGASUS_ENABLE_IPV6
853                                char ipBuffer[PEGASUS_INET6_ADDRSTR_LEN];
854 dev.meetei       1.134         if (System::getNameInfo(accept_address,
855 kumpf            1.131                 address_size,
856 dmitry.mikulin   1.106                 ipBuffer,
857 kumpf            1.131                 PEGASUS_INET6_ADDRSTR_LEN,
858                                        0,
859                                        0,
860 dev.meetei       1.134                 NI_NUMERICHOST))
861 dave.sudlik      1.101         {
862                                    delete accept_address;
863                                    return;
864                                }
865                                ipAddress = ipBuffer;
866                        #else
867 kumpf            1.92          unsigned char* sa = reinterpret_cast<unsigned char*>(
868                                    &reinterpret_cast<struct sockaddr_in*>(
869                                        accept_address)->sin_addr.s_addr);
870                                char ipBuffer[32];
871                                sprintf(ipBuffer, "%u.%u.%u.%u", sa[0], sa[1], sa[2], sa[3]);
872                                ipAddress = ipBuffer;
873 dave.sudlik      1.101 #endif
874 kumpf            1.92      }
875 karl             1.91  
876 kumpf            1.92      delete accept_address;
877 karl             1.91  
878                        // set the close on exec flag
879                        #if !defined(PEGASUS_OS_TYPE_WINDOWS) && !defined(PEGASUS_OS_VMS)
880 kumpf            1.92      int sock_flags;
881                            if ((sock_flags = fcntl(socket, F_GETFD, 0)) < 0)
882                            {
883 marek            1.124         PEG_TRACE_CSTRING(TRC_DISCARDED_DATA, Tracer::LEVEL1,
884 kumpf            1.92              "HTTPAcceptor: fcntl(F_GETFD) failed");
885                            }
886                            else
887                            {
888                                sock_flags |= FD_CLOEXEC;
889                                if (fcntl(socket, F_SETFD, sock_flags) < 0)
890                                {
891 marek            1.124             PEG_TRACE_CSTRING(TRC_DISCARDED_DATA, Tracer::LEVEL1,
892 kumpf            1.92                  "HTTPAcceptor: fcntl(F_SETFD) failed");
893                                }
894                            }
895 karl             1.91  #endif
896                        
897                        
898 r.kieninger      1.122     PEG_TRACE((
899                                TRC_HTTP,
900                                Tracer::LEVEL3,
901                                "HTTPAcceptor - accept() success.  Socket: %u",
902                                socket));
903 kumpf            1.92  
904 kumpf            1.96      SharedPtr<MP_Socket> mp_socket(new MP_Socket(
905 sushma.fernandes 1.97          socket, _sslcontext, _sslContextObjectLock, ipAddress));
906 kumpf            1.116     // mp_socket now has responsibility for closing the socket handle
907                            socketPtr.release();
908 kumpf            1.92  
909 kumpf            1.109     mp_socket->disableBlocking();
910 kumpf            1.131 
911 kavita.gupta     1.128     {
912                        #ifndef PEGASUS_INTEGERS_BOUNDARY_ALIGNED
913                                AutoMutex lock(_socketWriteTimeoutMutex);
914                        #endif
915                                mp_socket->setSocketWriteTimeout(_socketWriteTimeout);
916                            }
917 kumpf            1.92  
918 kumpf            1.109     // Perform the SSL handshake, if applicable.
919 kumpf            1.92  
920                            Sint32 socketAcceptStatus = mp_socket->accept();
921                        
922                            if (socketAcceptStatus < 0)
923                            {
924 marek            1.124         PEG_TRACE_CSTRING(TRC_DISCARDED_DATA, Tracer::LEVEL1,
925 kumpf            1.92              "HTTPAcceptor: SSL_accept() failed");
926                                return;
927                            }
928                        
929                            // Create a new connection and add it to the connection list:
930                        
931 kumpf            1.116     AutoPtr<HTTPConnection> connection(new HTTPConnection(
932                                _monitor,
933                                mp_socket,
934                                ipAddress,
935                                this,
936 kumpf            1.123         _outputMessageQueue));
937 kumpf            1.92  
938 kavita.gupta     1.128     if (HTTPConnection::getIdleConnectionTimeout())
939 dave.sudlik      1.108     {
940                                Time::gettimeofday(&connection->_idleStartTime);
941                            }
942                        
943 kumpf            1.92      if (socketAcceptStatus == 0)
944                            {
945 marek            1.124         PEG_TRACE_CSTRING(TRC_HTTP, Tracer::LEVEL1,
946 kumpf            1.92              "HTTPAcceptor: SSL_accept() pending");
947                                connection->_acceptPending = true;
948 dave.sudlik      1.108         Time::gettimeofday(&connection->_acceptPendingStartTime);
949 kumpf            1.92      }
950 karl             1.91  
951 kumpf            1.92      // Solicit events on this new connection's socket:
952                            int index;
953 karl             1.91  
954 kumpf            1.92      if (-1 ==  (index = _monitor->solicitSocketMessages(
955                                    connection->getSocket(),
956                                    SocketMessage::READ | SocketMessage::EXCEPTION,
957 kumpf            1.107             connection->getQueueId(), MonitorEntry::TYPE_CONNECTION)) )
958 kumpf            1.92      {
959 marek            1.124         PEG_TRACE_CSTRING(TRC_DISCARDED_DATA, Tracer::LEVEL1,
960 kumpf            1.92              "HTTPAcceptor::_acceptConnection: Attempt to allocate entry in "
961                                        "_entries table failed.");
962                                return;
963                            }
964 karl             1.91  
965 kumpf            1.92      connection->_entry_index = index;
966                            AutoMutex autoMut(_rep->_connection_mut);
967 kumpf            1.116     _rep->connections.append(connection.get());
968                            connection.release();
969 karl             1.91  }
970                        
971 kumpf            1.92  PEGASUS_NAMESPACE_END

No CVS admin address has been configured
Powered by
ViewCVS 0.9.2