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

No CVS admin address has been configured
Powered by
ViewCVS 0.9.2