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

  1 martin 1.129 //%LICENSE////////////////////////////////////////////////////////////////
  2 martin 1.130 //
  3 martin 1.129 // Licensed to The Open Group (TOG) under one or more contributor license
  4              // agreements.  Refer to the OpenPegasusNOTICE.txt file distributed with
  5              // this work for additional information regarding copyright ownership.
  6              // Each contributor licenses this file to you under the OpenPegasus Open
  7              // Source License; you may not use this file except in compliance with the
  8              // License.
  9 martin 1.130 //
 10 martin 1.129 // Permission is hereby granted, free of charge, to any person obtaining a
 11              // copy of this software and associated documentation files (the "Software"),
 12              // to deal in the Software without restriction, including without limitation
 13              // the rights to use, copy, modify, merge, publish, distribute, sublicense,
 14              // and/or sell copies of the Software, and to permit persons to whom the
 15              // Software is furnished to do so, subject to the following conditions:
 16 martin 1.130 //
 17 martin 1.129 // The above copyright notice and this permission notice shall be included
 18              // in all copies or substantial portions of the Software.
 19 martin 1.130 //
 20 martin 1.129 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
 21 martin 1.130 // OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
 22 martin 1.129 // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
 23              // IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
 24              // CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
 25              // TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
 26              // SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
 27 martin 1.130 //
 28 martin 1.129 //////////////////////////////////////////////////////////////////////////
 29 karl   1.91  //
 30              //%/////////////////////////////////////////////////////////////////////////////
 31              
 32              #include "Config.h"
 33              #include "Constants.h"
 34              #include <iostream>
 35              
 36              #include "Network.h"
 37              #include "Socket.h"
 38              #include "TLS.h"
 39              #include "HTTPAcceptor.h"
 40              #include "HTTPConnection.h"
 41 dave.sudlik 1.101 #include "HostAddress.h"
 42 karl        1.91  #include "Tracer.h"
 43 kumpf       1.93  #include <Pegasus/Common/MessageLoader.h>
 44 karl        1.91  
 45 ouyang.jian 1.102 #ifdef PEGASUS_OS_PASE
 46                   # include <as400_protos.h>
 47                   # include <Pegasus/Common/PaseCcsid.h>
 48                   #endif
 49                   
 50 karl        1.91  PEGASUS_USING_STD;
 51                   
 52                   PEGASUS_NAMESPACE_BEGIN
 53                   
 54                   
 55 mateus.baur 1.103 static int _maxConnectionQueueLength = -1;
 56 karl        1.91  
 57 kumpf       1.131 Uint32 HTTPAcceptor::_socketWriteTimeout =
 58 kavita.gupta 1.128     PEGASUS_DEFAULT_SOCKETWRITE_TIMEOUT_SECONDS;
 59                    
 60                    #ifndef PEGASUS_INTEGERS_BOUNDARY_ALIGNED
 61                    Mutex HTTPAcceptor::_socketWriteTimeoutMutex;
 62                    #endif
 63                    
 64 karl         1.91  ////////////////////////////////////////////////////////////////////////////////
 65                    //
 66                    // HTTPAcceptorRep
 67                    //
 68                    ////////////////////////////////////////////////////////////////////////////////
 69                    
 70                    class HTTPAcceptorRep
 71                    {
 72                    public:
 73 dave.sudlik  1.101     HTTPAcceptorRep(Uint16 connectionType)
 74 karl         1.91      {
 75 dave.sudlik  1.101         if (connectionType == HTTPAcceptor::LOCAL_CONNECTION)
 76 karl         1.91          {
 77                    #ifndef PEGASUS_DISABLE_LOCAL_DOMAIN_SOCKET
 78 kumpf        1.92              address =
 79                                    reinterpret_cast<struct sockaddr*>(new struct sockaddr_un);
 80 karl         1.91              address_size = sizeof(struct sockaddr_un);
 81                    #else
 82                                PEGASUS_ASSERT(false);
 83                    #endif
 84                            }
 85 dave.sudlik  1.101 #ifdef PEGASUS_ENABLE_IPV6
 86                            else if (connectionType == HTTPAcceptor::IPV6_CONNECTION)
 87                            {
 88                                address =
 89                                    reinterpret_cast<struct sockaddr*>(new struct sockaddr_in6);
 90                                address_size = sizeof(struct sockaddr_in6);
 91                            }
 92                    #endif
 93                            else if (connectionType == HTTPAcceptor::IPV4_CONNECTION)
 94 karl         1.91          {
 95 kumpf        1.92              address =
 96                                    reinterpret_cast<struct sockaddr*>(new struct sockaddr_in);
 97 karl         1.91              address_size = sizeof(struct sockaddr_in);
 98                            }
 99 dave.sudlik  1.101         else
100                            {
101                                PEGASUS_ASSERT(false);
102 karl         1.91      }
103 dave.sudlik  1.101     }
104                    
105 karl         1.91      ~HTTPAcceptorRep()
106                        {
107 kumpf        1.116         closeSocket();
108 karl         1.91          delete address;
109                        }
110 kumpf        1.116 
111                        void closeSocket()
112                        {
113                            Socket::close(socket);
114                        }
115                    
116 karl         1.91      struct sockaddr* address;
117                    
118                        SocketLength address_size;
119                        Mutex _connection_mut;
120                    
121                        SocketHandle socket;
122                        Array<HTTPConnection*> connections;
123                    };
124                    
125                    
126                    ////////////////////////////////////////////////////////////////////////////////
127                    //
128                    // HTTPAcceptor
129                    //
130                    ////////////////////////////////////////////////////////////////////////////////
131                    
132                    HTTPAcceptor::HTTPAcceptor(Monitor* monitor,
133                                               MessageQueue* outputMessageQueue,
134 dave.sudlik  1.101                            Uint16 connectionType,
135 karl         1.91                             Uint32 portNumber,
136                                               SSLContext * sslcontext,
137 dev.meetei   1.132                            ReadWriteSem* sslContextObjectLock,
138                                               HostAddress *listenOn)
139 karl         1.91     : Base(PEGASUS_QUEUENAME_HTTPACCEPTOR),  // ATTN: Need unique names?
140                         _monitor(monitor),
141                         _outputMessageQueue(outputMessageQueue),
142                         _rep(0),
143                         _entry_index(-1),
144 dave.sudlik  1.101      _connectionType(connectionType),
145 karl         1.91       _portNumber(portNumber),
146                         _sslcontext(sslcontext),
147 dev.meetei   1.132     _sslContextObjectLock(sslContextObjectLock),
148                        _listenAddress(listenOn)
149 karl         1.91  {
150 ouyang.jian  1.121    PEGASUS_ASSERT(!_sslcontext == !_sslContextObjectLock);
151 karl         1.91     Socket::initializeInterface();
152                    
153                       /*
154 mateus.baur  1.103         Platforms interpret the value of _maxConnectionQueueLength
155 kumpf        1.92          differently.  Some platforms interpret the value literally, while
156                            others multiply a fudge factor. When the server is under stress from
157                            multiple clients with multiple requests, toggling this number may
158                            prevent clients from being dropped.  Instead of hard coding the
159                            value, we allow an environment variable to be set which specifies a
160                            number greater than the maximum concurrent client connections
161                            possible.  If this environment var is not specified, then
162 mateus.baur  1.103         _maxConnectionQueueLength = 15.
163 karl         1.91     */
164                    
165 kumpf        1.92  //To engage runtime backlog queue length: uncomment the following block AND
166 mateus.baur  1.103 //comment out the line _maxConnectionQueueLength = 15
167 karl         1.91  
168                    /*
169 mateus.baur  1.103     if (_maxConnectionQueueLength == -1)
170 kumpf        1.92      {
171                            const char* env = getenv("PEGASUS_MAX_BACKLOG_CONNECTION_QUEUE");
172                            if (!env)
173                            {
174 mateus.baur  1.103             _maxConnectionQueueLength = 15;
175 kumpf        1.92          }
176                            else
177                            {
178                                char* end = NULL;
179 mateus.baur  1.103             _maxConnectionQueueLength = strtol(env, &end, 10);
180 kumpf        1.92              if (*end)
181 mateus.baur  1.103                 _maxConnectionQueueLength = 15;
182                                cout << " _maxConnectionQueueLength = " <<
183                                    _maxConnectionQueueLength << endl;
184 kumpf        1.92          }
185 karl         1.91      }
186                    */
187 mateus.baur  1.103 #ifdef PEGASUS_WMIMAPPER
188                        //The WMI Mapper can be used as a proxy to multiple WMI Servers.
189                        //If a client application simultaneously initiates connections
190                        //to many Windows systems, many of these connections may be routed
191                        //to a single WMI Mapper. A larger _maxConnectionQueueLength
192                        //value is required to allow these connections to be initiated
193                        //successfully.
194                        _maxConnectionQueueLength = 40;
195                    #else
196                        _maxConnectionQueueLength = 15;
197                    #endif
198 karl         1.91  }
199                    
200                    HTTPAcceptor::~HTTPAcceptor()
201                    {
202 kumpf        1.92      destroyConnections();
203                        unbind();
204                        // ATTN: Is this correct in a multi-HTTPAcceptor server?
205                        Socket::uninitializeInterface();
206 karl         1.91  }
207                    
208                    void HTTPAcceptor::handleEnqueue(Message *message)
209                    {
210 kumpf        1.92      if (!message)
211                           return;
212                    
213                        PEGASUS_ASSERT(_rep != 0);
214                        switch (message->getType())
215                        {
216                            case SOCKET_MESSAGE:
217                            {
218                                // 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 sushma.fernandes 1.117            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 kumpf            1.92          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                                PEGASUS_ASSERT(false);
403                            }
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 dave.sudlik      1.101         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 kumpf            1.92              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 kumpf            1.92              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 dev.meetei       1.132                     reinterpret_cast<struct sockaddr_un*>
706                                            (_rep->address)->sun_path);
707 karl             1.91  #else
708 kumpf            1.92              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 kumpf            1.92          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 dev.meetei       1.134         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 dev.meetei       1.134                 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