(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 dl.meetei    1.137             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 dl.meetei    1.137             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 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                                // If this is a connection request:
219 marek        1.136             PEGASUS_ASSERT(((SocketMessage*)message)->socket == _rep->socket);
220 kumpf        1.92  
221 marek        1.136             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 dl.meetei        1.137            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 dev.meetei       1.132 
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 dl.meetei        1.137         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 dev.meetei       1.132         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 ashok.pathak     1.133                 HostAddress::convertTextToBinary(AF_INET6, 
348 dev.meetei       1.132                 (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 ashok.pathak     1.133                 HostAddress::convertTextToBinary(AF_INET6, 
359 dev.meetei       1.132                 (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 dev.meetei       1.132         }
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 dev.meetei       1.132         if(_listenAddress)
379                                {
380                                    String hostAdd = _listenAddress->getHost();
381                                    CString ip = hostAdd.getCString();
382                                    struct sockaddr_in addrs;
383 ashok.pathak     1.133             HostAddress::convertTextToBinary(
384 dev.meetei       1.132                 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 dl.meetei        1.137         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 dl.meetei        1.137         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 dev.meetei       1.132                 "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 dev.meetei       1.132             "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 dev.meetei       1.132                     reinterpret_cast<struct sockaddr_un*>
591                                                (_rep->address)->sun_path);
592 karl             1.91  #else
593 dl.meetei        1.137             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 dev.meetei       1.132                     reinterpret_cast<struct sockaddr_un*>(
641                                                _rep->address)->sun_path);
642 karl             1.91  #else
643 dl.meetei        1.137             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 jsafrane         1.138 /**
678                            getListenAddress - Returns bind address
679                        */
680                        String HTTPAcceptor::getListenAddress() const
681                        {
682                            return _listenAddress ? _listenAddress->getHost() : String();
683                        }
684 karl             1.91  
685                        /**
686                            getPortNumber - returns the port number used for the connection
687                        */
688                        Uint32 HTTPAcceptor::getPortNumber() const
689                        {
690                            return _portNumber;
691                        }
692                        
693                        void HTTPAcceptor::setSocketWriteTimeout(Uint32 socketWriteTimeout)
694                        {
695 kavita.gupta     1.128 #ifndef PEGASUS_INTEGERS_BOUNDARY_ALIGNED
696                            AutoMutex lock(_socketWriteTimeoutMutex);
697                        #endif
698 karl             1.91      _socketWriteTimeout = socketWriteTimeout;
699                        }
700                        
701                        void HTTPAcceptor::unbind()
702                        {
703 kumpf            1.92      if (_rep)
704                            {
705                                _portNumber = 0;
706 kumpf            1.116         _rep->closeSocket();
707 karl             1.91  
708 dave.sudlik      1.101         if (_connectionType == LOCAL_CONNECTION)
709 kumpf            1.92          {
710 karl             1.91  #ifndef PEGASUS_DISABLE_LOCAL_DOMAIN_SOCKET
711 kumpf            1.92              ::unlink(
712 dev.meetei       1.132                     reinterpret_cast<struct sockaddr_un*>
713                                            (_rep->address)->sun_path);
714 karl             1.91  #else
715 dl.meetei        1.137             PEGASUS_UNREACHABLE(PEGASUS_ASSERT(false);)
716 karl             1.91  #endif
717 kumpf            1.92          }
718 karl             1.91  
719 kumpf            1.92          delete _rep;
720                                _rep = 0;
721                            }
722                            else
723                            {
724 marek            1.124         PEG_TRACE_CSTRING(TRC_HTTP, Tracer::LEVEL1,
725 kumpf            1.92              "HTTPAcceptor::unbind failure _rep is null." );
726                            }
727 karl             1.91  }
728                        
729                        void HTTPAcceptor::destroyConnections()
730                        {
731 kumpf            1.92      if (_rep)
732                            {
733                                // For each connection created by this object:
734 karl             1.91  
735 kumpf            1.92          AutoMutex autoMut(_rep->_connection_mut);
736                                for (Uint32 i = 0, n = _rep->connections.size(); i < n; i++)
737                                {
738                                    HTTPConnection* connection = _rep->connections[i];
739                                    SocketHandle socket = connection->getSocket();
740 karl             1.91  
741 kumpf            1.92              // Unsolicit SocketMessages:
742 karl             1.91  
743 kumpf            1.92              _monitor->unsolicitSocketMessages(socket);
744 karl             1.91  
745 kumpf            1.92              // Destroy the connection (causing it to close):
746 karl             1.91  
747 kumpf            1.92              while (connection->refcount.get()) { }
748                                    delete connection;
749                                }
750 karl             1.91  
751 kumpf            1.92          _rep->connections.clear();
752                            }
753 karl             1.91  }
754                        
755                        void HTTPAcceptor::_acceptConnection()
756                        {
757 kumpf            1.92      // This function cannot be called on an invalid socket!
758 karl             1.91  
759 kumpf            1.92      PEGASUS_ASSERT(_rep != 0);
760 karl             1.91  
761 kumpf            1.92      // Accept the connection (populate the address):
762 karl             1.91  
763 kumpf            1.92      struct sockaddr* accept_address;
764                            SocketLength address_size;
765 karl             1.91  
766 dave.sudlik      1.101     if (_connectionType == LOCAL_CONNECTION)
767 kumpf            1.92      {
768 karl             1.91  #ifndef PEGASUS_DISABLE_LOCAL_DOMAIN_SOCKET
769 kumpf            1.92          accept_address =
770                                    reinterpret_cast<struct sockaddr*>(new struct sockaddr_un);
771                                address_size = sizeof(struct sockaddr_un);
772 karl             1.91  #else
773 dl.meetei        1.137         PEGASUS_UNREACHABLE(PEGASUS_ASSERT(false);)
774 karl             1.91  #endif
775 kumpf            1.92      }
776                            else
777                            {
778 dave.sudlik      1.101 #ifdef PEGASUS_ENABLE_IPV6
779                                accept_address =
780                                   reinterpret_cast<struct sockaddr*>
781                                   (new struct sockaddr_storage);
782                                address_size = sizeof(struct sockaddr_storage);
783                        #else
784 kumpf            1.92          accept_address =
785                                    reinterpret_cast<struct sockaddr*>(new struct sockaddr_in);
786                                address_size = sizeof(struct sockaddr_in);
787 dave.sudlik      1.101 #endif
788 kumpf            1.92      }
789                        
790 kumpf            1.109     // It is not necessary to handle EINTR errors from this accept() call.
791                            // An EINTR error should not occur on a non-blocking socket.  If the
792                            // listen socket is blocking and EINTR occurs, the new socket connection
793                            // is not accepted here.
794                        
795                            // EAGAIN errors are also not handled here.  An EAGAIN error should not
796                            // occur after select() indicates that the listen socket is available for
797                            // reading.  If the accept() fails with an EAGAIN error code, a new
798                            // connection is not accepted here.
799                        
800                            SocketHandle socket = accept(_rep->socket, accept_address, &address_size);
801 kumpf            1.92  
802                            if (socket == PEGASUS_SOCKET_ERROR)
803                            {
804                                // the remote connection is invalid, destroy client address.
805                                delete accept_address;
806                        
807                                // TCPIP is down reconnect this acceptor
808                                if (getSocketError() == PEGASUS_NETWORK_TCPIP_STOPPED)
809                                {
810 marek            1.124             PEG_TRACE_CSTRING(TRC_DISCARDED_DATA, Tracer::LEVEL1,
811 kumpf            1.92                  "Socket has an IO error. TCP/IP down. Try to reconnect.");
812                        
813                                    reconnectConnectionSocket();
814                        
815                                    return;
816                                }
817 marek            1.119         PEG_TRACE((
818                                    TRC_DISCARDED_DATA,
819 marek            1.120             Tracer::LEVEL1,
820 marek            1.119             "HTTPAcceptor: accept() failed.  errno: %u",
821                                    errno));
822 kumpf            1.92          return;
823                            }
824 kumpf            1.116 
825                            // Use an AutoPtr to ensure the socket handle is closed on exception
826                            AutoPtr<SocketHandle, CloseSocketHandle> socketPtr(&socket);
827                        
828 marek            1.114 #ifndef PEGASUS_OS_TYPE_WINDOWS
829 marek            1.111     // We need to ensure that the socket number is not higher than
830                            // what fits into FD_SETSIZE, because we else won't be able to select on it
831                            // and won't ever communicate correct on that socket.
832                            if (socket >= FD_SETSIZE)
833                            {
834                                // the remote connection is invalid, destroy client address.
835                                delete accept_address;
836                        
837                                PEG_TRACE(
838                                    (TRC_DISCARDED_DATA,
839 marek            1.120              Tracer::LEVEL1,
840 kumpf            1.131              "HTTPAcceptor out of available sockets."
841 marek            1.119                  "accept() returned too large socket number %u."
842                                         "Closing connection to the new client.",
843 marek            1.111              socket));
844 kumpf            1.131 
845 marek            1.111         return;
846                            }
847 marek            1.114 #endif
848 karl             1.91  
849 kumpf            1.92      String ipAddress;
850 karl             1.91  
851 dave.sudlik      1.101     if (_connectionType == LOCAL_CONNECTION)
852 kumpf            1.92      {
853                                ipAddress = "localhost";
854                            }
855                            else
856                            {
857 dave.sudlik      1.101 #ifdef PEGASUS_ENABLE_IPV6
858                                char ipBuffer[PEGASUS_INET6_ADDRSTR_LEN];
859 dev.meetei       1.134         if (System::getNameInfo(accept_address,
860 kumpf            1.131                 address_size,
861 dmitry.mikulin   1.106                 ipBuffer,
862 kumpf            1.131                 PEGASUS_INET6_ADDRSTR_LEN,
863                                        0,
864                                        0,
865 dev.meetei       1.134                 NI_NUMERICHOST))
866 dave.sudlik      1.101         {
867                                    delete accept_address;
868                                    return;
869                                }
870                                ipAddress = ipBuffer;
871                        #else
872 kumpf            1.92          unsigned char* sa = reinterpret_cast<unsigned char*>(
873                                    &reinterpret_cast<struct sockaddr_in*>(
874                                        accept_address)->sin_addr.s_addr);
875                                char ipBuffer[32];
876                                sprintf(ipBuffer, "%u.%u.%u.%u", sa[0], sa[1], sa[2], sa[3]);
877                                ipAddress = ipBuffer;
878 dave.sudlik      1.101 #endif
879 kumpf            1.92      }
880 karl             1.91  
881 kumpf            1.92      delete accept_address;
882 karl             1.91  
883                        // set the close on exec flag
884                        #if !defined(PEGASUS_OS_TYPE_WINDOWS) && !defined(PEGASUS_OS_VMS)
885 kumpf            1.92      int sock_flags;
886                            if ((sock_flags = fcntl(socket, F_GETFD, 0)) < 0)
887                            {
888 marek            1.124         PEG_TRACE_CSTRING(TRC_DISCARDED_DATA, Tracer::LEVEL1,
889 kumpf            1.92              "HTTPAcceptor: fcntl(F_GETFD) failed");
890                            }
891                            else
892                            {
893                                sock_flags |= FD_CLOEXEC;
894                                if (fcntl(socket, F_SETFD, sock_flags) < 0)
895                                {
896 marek            1.124             PEG_TRACE_CSTRING(TRC_DISCARDED_DATA, Tracer::LEVEL1,
897 kumpf            1.92                  "HTTPAcceptor: fcntl(F_SETFD) failed");
898                                }
899                            }
900 karl             1.91  #endif
901                        
902                        
903 r.kieninger      1.122     PEG_TRACE((
904                                TRC_HTTP,
905                                Tracer::LEVEL3,
906                                "HTTPAcceptor - accept() success.  Socket: %u",
907                                socket));
908 kumpf            1.92  
909 kumpf            1.96      SharedPtr<MP_Socket> mp_socket(new MP_Socket(
910 sushma.fernandes 1.97          socket, _sslcontext, _sslContextObjectLock, ipAddress));
911 kumpf            1.116     // mp_socket now has responsibility for closing the socket handle
912                            socketPtr.release();
913 kumpf            1.92  
914 kumpf            1.109     mp_socket->disableBlocking();
915 kumpf            1.131 
916 kavita.gupta     1.128     {
917                        #ifndef PEGASUS_INTEGERS_BOUNDARY_ALIGNED
918                                AutoMutex lock(_socketWriteTimeoutMutex);
919                        #endif
920                                mp_socket->setSocketWriteTimeout(_socketWriteTimeout);
921                            }
922 kumpf            1.92  
923 kumpf            1.109     // Perform the SSL handshake, if applicable.
924 kumpf            1.92  
925                            Sint32 socketAcceptStatus = mp_socket->accept();
926                        
927                            if (socketAcceptStatus < 0)
928                            {
929 marek            1.124         PEG_TRACE_CSTRING(TRC_DISCARDED_DATA, Tracer::LEVEL1,
930 kumpf            1.92              "HTTPAcceptor: SSL_accept() failed");
931                                return;
932                            }
933                        
934                            // Create a new connection and add it to the connection list:
935                        
936 kumpf            1.116     AutoPtr<HTTPConnection> connection(new HTTPConnection(
937                                _monitor,
938                                mp_socket,
939                                ipAddress,
940                                this,
941 kumpf            1.123         _outputMessageQueue));
942 kumpf            1.92  
943 kavita.gupta     1.128     if (HTTPConnection::getIdleConnectionTimeout())
944 dave.sudlik      1.108     {
945                                Time::gettimeofday(&connection->_idleStartTime);
946                            }
947                        
948 kumpf            1.92      if (socketAcceptStatus == 0)
949                            {
950 marek            1.124         PEG_TRACE_CSTRING(TRC_HTTP, Tracer::LEVEL1,
951 kumpf            1.92              "HTTPAcceptor: SSL_accept() pending");
952                                connection->_acceptPending = true;
953 dave.sudlik      1.108         Time::gettimeofday(&connection->_acceptPendingStartTime);
954 kumpf            1.92      }
955 karl             1.91  
956 kumpf            1.92      // Solicit events on this new connection's socket:
957                            int index;
958 karl             1.91  
959 kumpf            1.92      if (-1 ==  (index = _monitor->solicitSocketMessages(
960                                    connection->getSocket(),
961 kumpf            1.107             connection->getQueueId(), MonitorEntry::TYPE_CONNECTION)) )
962 kumpf            1.92      {
963 marek            1.124         PEG_TRACE_CSTRING(TRC_DISCARDED_DATA, Tracer::LEVEL1,
964 kumpf            1.92              "HTTPAcceptor::_acceptConnection: Attempt to allocate entry in "
965                                        "_entries table failed.");
966                                return;
967                            }
968 karl             1.91  
969 kumpf            1.92      connection->_entry_index = index;
970                            AutoMutex autoMut(_rep->_connection_mut);
971 kumpf            1.116     _rep->connections.append(connection.get());
972                            connection.release();
973 karl             1.91  }
974                        
975 kumpf            1.92  PEGASUS_NAMESPACE_END

No CVS admin address has been configured
Powered by
ViewCVS 0.9.2