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

  1 karl  1.91 //%2006////////////////////////////////////////////////////////////////////////
  2            //
  3            // Copyright (c) 2000, 2001, 2002 BMC Software; Hewlett-Packard Development
  4            // Company, L.P.; IBM Corp.; The Open Group; Tivoli Systems.
  5            // Copyright (c) 2003 BMC Software; Hewlett-Packard Development Company, L.P.;
  6            // IBM Corp.; EMC Corporation, The Open Group.
  7            // Copyright (c) 2004 BMC Software; Hewlett-Packard Development Company, L.P.;
  8            // IBM Corp.; EMC Corporation; VERITAS Software Corporation; The Open Group.
  9            // Copyright (c) 2005 Hewlett-Packard Development Company, L.P.; IBM Corp.;
 10            // EMC Corporation; VERITAS Software Corporation; The Open Group.
 11            // Copyright (c) 2006 Hewlett-Packard Development Company, L.P.; IBM Corp.;
 12            // EMC Corporation; Symantec Corporation; The Open Group.
 13            //
 14            // Permission is hereby granted, free of charge, to any person obtaining a copy
 15            // of this software and associated documentation files (the "Software"), to
 16            // deal in the Software without restriction, including without limitation the
 17            // rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
 18            // sell copies of the Software, and to permit persons to whom the Software is
 19            // furnished to do so, subject to the following conditions:
 20            //
 21            // THE ABOVE COPYRIGHT NOTICE AND THIS PERMISSION NOTICE SHALL BE INCLUDED IN
 22 karl  1.91 // ALL COPIES OR SUBSTANTIAL PORTIONS OF THE SOFTWARE. THE SOFTWARE IS PROVIDED
 23            // "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT
 24            // LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR
 25            // PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
 26            // HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
 27            // ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
 28            // WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
 29            //
 30            //==============================================================================
 31            //
 32            //%/////////////////////////////////////////////////////////////////////////////
 33            
 34            #include "Config.h"
 35            #include "Constants.h"
 36            #include <iostream>
 37            
 38            #include "Network.h"
 39            #include "Socket.h"
 40            #include "TLS.h"
 41            #include "HTTPAcceptor.h"
 42            #include "HTTPConnection.h"
 43 karl  1.91 #include "Tracer.h"
 44 kumpf 1.93 #include <Pegasus/Common/MessageLoader.h>
 45 karl  1.91 
 46            PEGASUS_USING_STD;
 47            
 48            PEGASUS_NAMESPACE_BEGIN
 49            
 50            
 51            static int MAX_CONNECTION_QUEUE_LENGTH = -1;
 52            
 53            ////////////////////////////////////////////////////////////////////////////////
 54            //
 55            // HTTPAcceptorRep
 56            //
 57            ////////////////////////////////////////////////////////////////////////////////
 58            
 59            class HTTPAcceptorRep
 60            {
 61            public:
 62                HTTPAcceptorRep(Boolean local)
 63                {
 64                    if (local)
 65                    {
 66 karl  1.91 #ifndef PEGASUS_DISABLE_LOCAL_DOMAIN_SOCKET
 67 kumpf 1.92             address =
 68                            reinterpret_cast<struct sockaddr*>(new struct sockaddr_un);
 69 karl  1.91             address_size = sizeof(struct sockaddr_un);
 70            #else
 71                        PEGASUS_ASSERT(false);
 72            #endif
 73                    }
 74                    else
 75                    {
 76 kumpf 1.92             address =
 77                            reinterpret_cast<struct sockaddr*>(new struct sockaddr_in);
 78 karl  1.91             address_size = sizeof(struct sockaddr_in);
 79                    }
 80                }
 81                ~HTTPAcceptorRep()
 82                {
 83                    delete address;
 84                }
 85                struct sockaddr* address;
 86            
 87                SocketLength address_size;
 88                Mutex _connection_mut;
 89            
 90                SocketHandle socket;
 91                Array<HTTPConnection*> connections;
 92            };
 93            
 94            
 95            ////////////////////////////////////////////////////////////////////////////////
 96            //
 97            // HTTPAcceptor
 98            //
 99 karl  1.91 ////////////////////////////////////////////////////////////////////////////////
100            
101            HTTPAcceptor::HTTPAcceptor(Monitor* monitor,
102                                       MessageQueue* outputMessageQueue,
103                                       Boolean localConnection,
104                                       Uint32 portNumber,
105                                       SSLContext * sslcontext,
106                                       ReadWriteSem* sslContextObjectLock)
107               : Base(PEGASUS_QUEUENAME_HTTPACCEPTOR),  // ATTN: Need unique names?
108                 _monitor(monitor),
109                 _outputMessageQueue(outputMessageQueue),
110                 _rep(0),
111                 _entry_index(-1),
112                 _localConnection(localConnection),
113                 _portNumber(portNumber),
114                 _sslcontext(sslcontext),
115                 _sslContextObjectLock(sslContextObjectLock)
116            {
117               Socket::initializeInterface();
118            
119               /*
120 kumpf 1.92         Platforms interpret the value of MAX_CONNECTION_QUEUE_LENGTH
121                    differently.  Some platforms interpret the value literally, while
122                    others multiply a fudge factor. When the server is under stress from
123                    multiple clients with multiple requests, toggling this number may
124                    prevent clients from being dropped.  Instead of hard coding the
125                    value, we allow an environment variable to be set which specifies a
126                    number greater than the maximum concurrent client connections
127                    possible.  If this environment var is not specified, then
128                    MAX_CONNECTION_QUEUE_LENGTH = 15.
129 karl  1.91    */
130            
131 kumpf 1.92 //To engage runtime backlog queue length: uncomment the following block AND
132            //comment out the line MAX_CONNECTION_QUEUE_LENGTH = 15
133 karl  1.91 
134            /*
135 kumpf 1.92     if (MAX_CONNECTION_QUEUE_LENGTH == -1)
136                {
137                    const char* env = getenv("PEGASUS_MAX_BACKLOG_CONNECTION_QUEUE");
138                    if (!env)
139                    {
140 karl  1.91             MAX_CONNECTION_QUEUE_LENGTH = 15;
141 kumpf 1.92         }
142                    else
143                    {
144                        char* end = NULL;
145                        MAX_CONNECTION_QUEUE_LENGTH = strtol(env, &end, 10);
146                        if (*end)
147                            MAX_CONNECTION_QUEUE_LENGTH = 15;
148                        cout << " MAX_CONNECTION_QUEUE_LENGTH = " <<
149                            MAX_CONNECTION_QUEUE_LENGTH << endl;
150                    }
151 karl  1.91     }
152            */
153 kumpf 1.92     MAX_CONNECTION_QUEUE_LENGTH = 15;
154 karl  1.91 }
155            
156            HTTPAcceptor::~HTTPAcceptor()
157            {
158 kumpf 1.92     destroyConnections();
159                unbind();
160                // ATTN: Is this correct in a multi-HTTPAcceptor server?
161                Socket::uninitializeInterface();
162 karl  1.91 }
163            
164            void HTTPAcceptor::handleEnqueue(Message *message)
165            {
166 kumpf 1.92     if (!message)
167                   return;
168            
169                PEGASUS_ASSERT(_rep != 0);
170                switch (message->getType())
171                {
172                    case SOCKET_MESSAGE:
173                    {
174                        SocketMessage* socketMessage = (SocketMessage*)message;
175            
176                        // If this is a connection request:
177            
178                        if (socketMessage->socket == _rep->socket &&
179                            socketMessage->events & SocketMessage::READ)
180                        {
181                            _acceptConnection();
182                        }
183                        else
184                        {
185                            // ATTN! this can't happen!
186 marek 1.95                 PEG_TRACE_CSTRING(TRC_DISCARDED_DATA, Tracer::LEVEL2,
187 kumpf 1.92                     "HTTPAcceptor::handleEnqueue: Invalid SOCKET_MESSAGE "
188                                    "received.");
189                       }
190 karl  1.91 
191                       break;
192 kumpf 1.92        }
193            
194                   case CLOSE_CONNECTION_MESSAGE:
195                   {
196                       CloseConnectionMessage* closeConnectionMessage =
197                           (CloseConnectionMessage*)message;
198            
199                       AutoMutex autoMut(_rep->_connection_mut);
200            
201                       for (Uint32 i = 0, n = _rep->connections.size(); i < n; i++)
202                       {
203                           HTTPConnection* connection = _rep->connections[i];
204                           SocketHandle socket = connection->getSocket();
205            
206                           if (socket == closeConnectionMessage->socket)
207                           {
208                               _monitor->unsolicitSocketMessages(socket);
209                               _rep->connections.remove(i);
210                               delete connection;
211                               break;
212                           }
213 kumpf 1.92            }
214 karl  1.91 
215 kumpf 1.92            break;
216                   }
217 karl  1.91 
218 kumpf 1.92        default:
219                       // ATTN: need unexpected message error!
220 marek 1.95            PEG_TRACE_CSTRING(TRC_DISCARDED_DATA, Tracer::LEVEL2,
221 kumpf 1.92                "HTTPAcceptor::handleEnqueue: Invalid MESSAGE received.");
222                       break;
223                }
224 karl  1.91 
225 kumpf 1.92     delete message;
226 karl  1.91 }
227            
228            
229            void HTTPAcceptor::handleEnqueue()
230            {
231 kumpf 1.92     Message* message = dequeue();
232 karl  1.91 
233 kumpf 1.92     if (!message)
234                {
235 marek 1.95         PEG_TRACE_CSTRING(TRC_DISCARDED_DATA, Tracer::LEVEL2,
236 kumpf 1.92             "HTTPAcceptor::handleEnqueue(): No message on queue.");
237                    return;
238                }
239 karl  1.91 
240 kumpf 1.92     handleEnqueue(message);
241 karl  1.91 }
242            
243            void HTTPAcceptor::bind()
244            {
245 kumpf 1.92     if (_rep)
246                {
247                    MessageLoaderParms parms("Common.HTTPAcceptor.ALREADY_BOUND",
248                        "HTTPAcceptor already bound");
249 karl  1.91 
250 marek 1.95         PEG_TRACE_CSTRING(TRC_DISCARDED_DATA, Tracer::LEVEL2,
251 kumpf 1.92             "HTTPAcceptor::bind: HTTPAcceptor already bound.");
252                    throw BindFailedException(parms);
253                }
254 karl  1.91 
255 kumpf 1.92     _rep = new HTTPAcceptorRep(_localConnection);
256 karl  1.91 
257 kumpf 1.92     // bind address
258                _bind();
259 karl  1.91 }
260            
261            /**
262 kumpf 1.92     _bind - creates a new server socket and bind socket to the port address.
263                If PEGASUS_DISABLE_LOCAL_DOMAIN_SOCKET is not defined, the port number is
264                ignored and a domain socket is bound.
265 karl  1.91 */
266            void HTTPAcceptor::_bind()
267            {
268 kumpf 1.92     PEGASUS_ASSERT(_rep != 0);
269                // Create address:
270 karl  1.91 
271 kumpf 1.92     memset(_rep->address, 0, sizeof(*_rep->address));
272 karl  1.91 
273 kumpf 1.92     if (_localConnection)
274                {
275 karl  1.91 #ifndef PEGASUS_DISABLE_LOCAL_DOMAIN_SOCKET
276 kumpf 1.100         //
277                     // Make sure the local domain socket can be owned by the cimserver
278                     // user.  Otherwise, the bind may fail with a vague "bind failed"
279                     // error.
280                     //
281                     if (System::exists(PEGASUS_LOCAL_DOMAIN_SOCKET_PATH))
282                     {
283                         if (!System::removeFile(PEGASUS_LOCAL_DOMAIN_SOCKET_PATH))
284                         {
285                             throw CannotRemoveFile(PEGASUS_LOCAL_DOMAIN_SOCKET_PATH);
286                         }
287                     }
288             
289 kumpf 1.92          reinterpret_cast<struct sockaddr_un*>(_rep->address)->sun_family =
290                         AF_UNIX;
291                     strcpy(reinterpret_cast<struct sockaddr_un*>(_rep->address)->sun_path,
292                         PEGASUS_LOCAL_DOMAIN_SOCKET_PATH);
293 karl  1.91  #else
294 kumpf 1.92          PEGASUS_ASSERT(false);
295 karl  1.91  #endif
296 kumpf 1.92      }
297                 else
298                 {
299                     reinterpret_cast<struct sockaddr_in*>(_rep->address)->sin_addr.s_addr =
300                         INADDR_ANY;
301                     reinterpret_cast<struct sockaddr_in*>(_rep->address)->sin_family =
302                         AF_INET;
303                     reinterpret_cast<struct sockaddr_in*>(_rep->address)->sin_port =
304                         htons(_portNumber);
305                 }
306             
307                 // Create socket:
308             
309                 if (_localConnection)
310                 {
311                     _rep->socket = Socket::createSocket(AF_UNIX, SOCK_STREAM, 0);
312                 }
313                 else
314                 {
315                     _rep->socket = Socket::createSocket(PF_INET, SOCK_STREAM, IPPROTO_TCP);
316                 }
317 kumpf 1.92  
318                 if (_rep->socket < 0)
319                 {
320                     delete _rep;
321                     _rep = 0;
322                     MessageLoaderParms parms("Common.HTTPAcceptor.FAILED_CREATE_SOCKET",
323                         "Failed to create socket");
324 marek 1.95          PEG_TRACE_CSTRING(TRC_DISCARDED_DATA, Tracer::LEVEL2,
325 kumpf 1.92              "HTTPAcceptor::_bind _rep->socket < 0");
326                     throw BindFailedException(parms);
327                 }
328 karl  1.91  
329             
330             // set the close-on-exec bit for this file handle.
331             // any unix that forks needs this bit set.
332             #if !defined PEGASUS_OS_TYPE_WINDOWS && !defined(PEGASUS_OS_VMS)
333 kumpf 1.92      int sock_flags;
334                 if ((sock_flags = fcntl(_rep->socket, F_GETFD, 0)) < 0)
335                 {
336 marek 1.95          PEG_TRACE_CSTRING(TRC_DISCARDED_DATA, Tracer::LEVEL2,
337 kumpf 1.92              "HTTPAcceptor::_bind: fcntl(F_GETFD) failed");
338                 }
339                 else
340                 {
341                     sock_flags |= FD_CLOEXEC;
342                     if (fcntl(_rep->socket, F_SETFD, sock_flags) < 0)
343                     {
344 marek 1.95              PEG_TRACE_CSTRING(TRC_DISCARDED_DATA, Tracer::LEVEL2,
345 kumpf 1.92                  "HTTPAcceptor::_bind: fcntl(F_SETFD) failed");
346                     }
347                 }
348             #endif
349             
350             
351                 //
352                 // Set the socket option SO_REUSEADDR to reuse the socket address so
353                 // that we can rebind to a new socket using the same address when we
354                 // need to resume the cimom as a result of a timeout during a Shutdown
355                 // operation.
356                 //
357                 int opt=1;
358                 if (setsockopt(_rep->socket, SOL_SOCKET, SO_REUSEADDR,
359                         (char *)&opt, sizeof(opt)) < 0)
360                 {
361                     Socket::close(_rep->socket);
362                     delete _rep;
363                     _rep = 0;
364                     MessageLoaderParms parms("Common.HTTPAcceptor.FAILED_SET_SOCKET_OPTION",
365                         "Failed to set socket option");
366 marek 1.95          PEG_TRACE_CSTRING(TRC_DISCARDED_DATA, Tracer::LEVEL2,
367 kumpf 1.92              "HTTPAcceptor::_bind: Failed to set socket option.");
368                     throw BindFailedException(parms);
369                 }
370             
371             
372                 //
373                 // Bind socket to port:
374                 //
375                 if (::bind(_rep->socket, _rep->address, _rep->address_size) < 0)
376                 {
377                     Socket::close(_rep->socket);
378                     delete _rep;
379                     _rep = 0;
380                     MessageLoaderParms parms("Common.HTTPAcceptor.FAILED_BIND_SOCKET",
381                         "Failed to bind socket");
382 marek 1.95          PEG_TRACE_CSTRING(TRC_DISCARDED_DATA, Tracer::LEVEL2,
383 kumpf 1.92              "HTTPAcceptor::_bind: Failed to bind socket.");
384                     throw BindFailedException(parms);
385                 }
386             
387             
388                 //
389                 // Get the actual port value used if the caller specified a port value of 0.
390                 //
391                 if (_portNumber == 0)
392                 {
393                     sockaddr_in buf;
394                     SocketLength bufSize = sizeof(buf);
395                     if (getsockname(_rep->socket, reinterpret_cast<sockaddr *>(&buf),
396                             &bufSize) == 0 )
397                     {
398                         _portNumber = ntohs(buf.sin_port);
399                     }
400                 }
401             
402             
403                 //
404 kumpf 1.92      // Change permissions on Linux local domain socket to allow writes by
405                 // others.
406                 //
407 karl  1.91  #if !defined(PEGASUS_DISABLE_LOCAL_DOMAIN_SOCKET) && \
408 kumpf 1.92       (defined(PEGASUS_PLATFORM_LINUX_GENERIC_GNU) || \
409                   defined(PEGASUS_PLATFORM_ZOS_ZSERIES_IBM))
410                 if (_localConnection)
411                 {
412                     if (::chmod(PEGASUS_LOCAL_DOMAIN_SOCKET_PATH,
413                             S_IRUSR | S_IWUSR | S_IXUSR |
414                             S_IRGRP | S_IWGRP | S_IXGRP |
415                             S_IROTH | S_IWOTH | S_IXOTH ) < 0 )
416                     {
417                         Socket::close(_rep->socket);
418                         delete _rep;
419                         _rep = 0;
420                         MessageLoaderParms parms("Common.HTTPAcceptor.FAILED_BIND_SOCKET",
421                             "Failed to bind socket");
422 marek 1.95              PEG_TRACE_CSTRING(TRC_DISCARDED_DATA, Tracer::LEVEL2,
423 kumpf 1.92                  "HTTPAcceptor::_bind: Failed to set domain socket "
424                                 "permissions.");
425                         throw BindFailedException(parms);
426                     }
427                 }
428             #endif
429             
430                 // Set up listening on the given socket:
431             
432                 //int const MAX_CONNECTION_QUEUE_LENGTH = 15;
433             
434                 if (listen(_rep->socket, MAX_CONNECTION_QUEUE_LENGTH) < 0)
435                 {
436                     Socket::close(_rep->socket);
437                     delete _rep;
438                     _rep = 0;
439                     MessageLoaderParms parms("Common.HTTPAcceptor.FAILED_BIND_SOCKET",
440                         "Failed to bind socket");
441 marek 1.95          PEG_TRACE_CSTRING(TRC_DISCARDED_DATA, Tracer::LEVEL2,
442 kumpf 1.92              "HTTPAcceptor::_bind: Failed to bind socket(1).");
443                     throw BindFailedException(parms);
444                 }
445             
446                 // Register to receive SocketMessages on this socket:
447             
448                 if (-1 == ( _entry_index = _monitor->solicitSocketMessages(
449                         _rep->socket,
450                         SocketMessage::READ | SocketMessage::EXCEPTION,
451                         getQueueId(),
452                         Monitor::ACCEPTOR)))
453                 {
454                     Socket::close(_rep->socket);
455                     delete _rep;
456                     _rep = 0;
457                     MessageLoaderParms parms(
458                         "Common.HTTPAcceptor.FAILED_SOLICIT_SOCKET_MESSAGES",
459                         "Failed to solicit socket messaeges");
460 marek 1.95          PEG_TRACE_CSTRING(TRC_DISCARDED_DATA, Tracer::LEVEL2,
461 kumpf 1.92              "HTTPAcceptor::_bind: Failed to solicit socket messages(2).");
462                     throw BindFailedException(parms);
463                 }
464 karl  1.91  }
465             
466             /**
467 kumpf 1.92      closeConnectionSocket - close the server listening socket to disallow
468                 new client connections.
469 karl  1.91  */
470             void HTTPAcceptor::closeConnectionSocket()
471             {
472 kumpf 1.92      if (_rep)
473                 {
474                     // unregister the socket
475             
476                     // ATTN - comment out - see CIMServer::stopClientConnection()
477                     //_monitor->unsolicitSocketMessages(_rep->socket);
478             
479                     // close the socket
480                     Socket::close(_rep->socket);
481                     // Unlink Local Domain Socket Bug# 3312
482                     if (_localConnection)
483                     {
484 karl  1.91  #ifndef PEGASUS_DISABLE_LOCAL_DOMAIN_SOCKET
485 marek 1.95              PEG_TRACE_CSTRING(TRC_HTTP, Tracer::LEVEL2,
486 kumpf 1.92                  "HTTPAcceptor::closeConnectionSocket Unlinking local "
487                                 "connection.");
488                         ::unlink(
489                             reinterpret_cast<struct sockaddr_un*>(_rep->address)->sun_path);
490 karl  1.91  #else
491 kumpf 1.92              PEGASUS_ASSERT(false);
492 karl  1.91  #endif
493 kumpf 1.92          }
494                 }
495                 else
496                 {
497 marek 1.95          PEG_TRACE_CSTRING(TRC_DISCARDED_DATA, Tracer::LEVEL2,
498 kumpf 1.92              "HTTPAcceptor::closeConnectionSocket failure _rep is null.");
499                 }
500 karl  1.91  }
501             
502             /**
503                reopenConnectionSocket - creates a new server socket.
504             */
505             void HTTPAcceptor::reopenConnectionSocket()
506             {
507 kumpf 1.92      if (_rep)
508                 {
509                     _bind();
510                 }
511                 else
512                 {
513 marek 1.95          PEG_TRACE_CSTRING(TRC_DISCARDED_DATA, Tracer::LEVEL2,
514 kumpf 1.92              "HTTPAcceptor::reopenConnectionSocket failure _rep is null.");
515                 }
516 karl  1.91  }
517             
518             
519             /**
520                reconnectConnectionSocket - creates a new server socket.
521             */
522             void HTTPAcceptor::reconnectConnectionSocket()
523             {
524 kumpf 1.92      if (_rep)
525                 {
526                     // unregister the socket
527                     _monitor->unsolicitSocketMessages(_rep->socket);
528                     // close the socket
529                     Socket::close(_rep->socket);
530                     // Unlink Local Domain Socket Bug# 3312
531                     if (_localConnection)
532                     {
533 karl  1.91  #ifndef PEGASUS_DISABLE_LOCAL_DOMAIN_SOCKET
534 marek 1.95              PEG_TRACE_CSTRING(TRC_HTTP, Tracer::LEVEL2,
535 kumpf 1.92                  "HTTPAcceptor::reconnectConnectionSocket Unlinking local "
536                                 "connection." );
537                         ::unlink(
538                             reinterpret_cast<struct sockaddr_un*>(_rep->address)->sun_path);
539 karl  1.91  #else
540 kumpf 1.92              PEGASUS_ASSERT(false);
541 karl  1.91  #endif
542 kumpf 1.92          }
543                     // open the socket
544                     _bind();
545                 }
546                 else
547                 {
548 marek 1.95          PEG_TRACE_CSTRING(TRC_DISCARDED_DATA, Tracer::LEVEL2,
549 kumpf 1.92              "HTTPAcceptor::reconnectConnectionSocket failure _rep is null.");
550                 }
551 karl  1.91  }
552             
553             /**
554 kumpf 1.92      getOutstandingRequestCount - returns the number of outstanding requests.
555 karl  1.91  */
556             Uint32 HTTPAcceptor::getOutstandingRequestCount() const
557             {
558 kumpf 1.92      Uint32 count = 0;
559                 if (_rep)
560                 {
561                     AutoMutex autoMut(_rep->_connection_mut);
562                     if (_rep->connections.size() > 0)
563                     {
564                         HTTPConnection* connection = _rep->connections[0];
565                         count = connection->getRequestCount();
566                     }
567                 }
568                 return count;
569 karl  1.91  }
570             
571             
572             /**
573                 getPortNumber - returns the port number used for the connection
574             */
575             Uint32 HTTPAcceptor::getPortNumber() const
576             {
577                 return _portNumber;
578             }
579             
580             void HTTPAcceptor::setSocketWriteTimeout(Uint32 socketWriteTimeout)
581             {
582                 _socketWriteTimeout = socketWriteTimeout;
583             }
584             
585             void HTTPAcceptor::unbind()
586             {
587 kumpf 1.92      if (_rep)
588                 {
589                     _portNumber = 0;
590                     Socket::close(_rep->socket);
591 karl  1.91  
592 kumpf 1.92          if (_localConnection)
593                     {
594 karl  1.91  #ifndef PEGASUS_DISABLE_LOCAL_DOMAIN_SOCKET
595 kumpf 1.92              ::unlink(
596                             reinterpret_cast<struct sockaddr_un*>(_rep->address)->sun_path);
597 karl  1.91  #else
598 kumpf 1.92              PEGASUS_ASSERT(false);
599 karl  1.91  #endif
600 kumpf 1.92          }
601 karl  1.91  
602 kumpf 1.92          delete _rep;
603                     _rep = 0;
604                 }
605                 else
606                 {
607 marek 1.95          PEG_TRACE_CSTRING(TRC_DISCARDED_DATA, Tracer::LEVEL2,
608 kumpf 1.92              "HTTPAcceptor::unbind failure _rep is null." );
609                 }
610 karl  1.91  }
611             
612             void HTTPAcceptor::destroyConnections()
613             {
614 kumpf 1.92      if (_rep)
615                 {
616                     // For each connection created by this object:
617 karl  1.91  
618 kumpf 1.92          AutoMutex autoMut(_rep->_connection_mut);
619                     for (Uint32 i = 0, n = _rep->connections.size(); i < n; i++)
620                     {
621                         HTTPConnection* connection = _rep->connections[i];
622                         SocketHandle socket = connection->getSocket();
623 karl  1.91  
624 kumpf 1.92              // Unsolicit SocketMessages:
625 karl  1.91  
626 kumpf 1.92              _monitor->unsolicitSocketMessages(socket);
627 karl  1.91  
628 kumpf 1.92              // Destroy the connection (causing it to close):
629 karl  1.91  
630 kumpf 1.92              while (connection->refcount.get()) { }
631                         delete connection;
632                     }
633 karl  1.91  
634 kumpf 1.92          _rep->connections.clear();
635                 }
636 karl  1.91  }
637             
638             void HTTPAcceptor::_acceptConnection()
639             {
640 kumpf 1.92      // This function cannot be called on an invalid socket!
641 karl  1.91  
642 kumpf 1.92      PEGASUS_ASSERT(_rep != 0);
643 karl  1.91  
644 kumpf 1.92      // Accept the connection (populate the address):
645 karl  1.91  
646 kumpf 1.92      struct sockaddr* accept_address;
647                 SocketLength address_size;
648 karl  1.91  
649 kumpf 1.92      if (_localConnection)
650                 {
651 karl  1.91  #ifndef PEGASUS_DISABLE_LOCAL_DOMAIN_SOCKET
652 kumpf 1.92          accept_address =
653                         reinterpret_cast<struct sockaddr*>(new struct sockaddr_un);
654                     address_size = sizeof(struct sockaddr_un);
655 karl  1.91  #else
656 kumpf 1.92          PEGASUS_ASSERT(false);
657 karl  1.91  #endif
658 kumpf 1.92      }
659                 else
660                 {
661                     accept_address =
662                         reinterpret_cast<struct sockaddr*>(new struct sockaddr_in);
663                     address_size = sizeof(struct sockaddr_in);
664                 }
665             
666 dave.sudlik 1.94      SocketHandle socket;
667                   #ifdef PEGASUS_OS_TYPE_WINDOWS
668                       socket = accept(_rep->socket, accept_address, &address_size);
669                   #else
670                       while (
671                           ((socket = accept(_rep->socket, accept_address, &address_size)) == -1)
672                           && (errno == EINTR))
673                           ;
674                   #endif
675 kumpf       1.92  
676                       if (socket == PEGASUS_SOCKET_ERROR)
677                       {
678                           // the remote connection is invalid, destroy client address.
679                           delete accept_address;
680                   
681                           // TCPIP is down reconnect this acceptor
682                           if (getSocketError() == PEGASUS_NETWORK_TCPIP_STOPPED)
683                           {
684 marek       1.95              PEG_TRACE_CSTRING(TRC_DISCARDED_DATA, Tracer::LEVEL2,
685 kumpf       1.92                  "Socket has an IO error. TCP/IP down. Try to reconnect.");
686                   
687                               reconnectConnectionSocket();
688                   
689                               return;
690                           }
691 karl        1.91  
692 kumpf       1.92          Logger::put(Logger::STANDARD_LOG, System::CIMSERVER, Logger::TRACE,
693                               "HTTPAcceptor - accept() failure.  errno: $0", errno);
694 karl        1.91  
695 marek       1.95          PEG_TRACE_CSTRING(TRC_DISCARDED_DATA, Tracer::LEVEL2,
696 kumpf       1.92              "HTTPAcceptor: accept() failed");
697                           return;
698                       }
699 karl        1.91  
700 kumpf       1.92      String ipAddress;
701 karl        1.91  
702 kumpf       1.92      if (_localConnection)
703                       {
704                           ipAddress = "localhost";
705                       }
706                       else
707                       {
708                           unsigned char* sa = reinterpret_cast<unsigned char*>(
709                               &reinterpret_cast<struct sockaddr_in*>(
710                                   accept_address)->sin_addr.s_addr);
711                           char ipBuffer[32];
712                           sprintf(ipBuffer, "%u.%u.%u.%u", sa[0], sa[1], sa[2], sa[3]);
713                           ipAddress = ipBuffer;
714                       }
715 karl        1.91  
716 kumpf       1.92      delete accept_address;
717 karl        1.91  
718                   // set the close on exec flag
719                   #if !defined(PEGASUS_OS_TYPE_WINDOWS) && !defined(PEGASUS_OS_VMS)
720 kumpf       1.92      int sock_flags;
721                       if ((sock_flags = fcntl(socket, F_GETFD, 0)) < 0)
722                       {
723 marek       1.95          PEG_TRACE_CSTRING(TRC_DISCARDED_DATA, Tracer::LEVEL2,
724 kumpf       1.92              "HTTPAcceptor: fcntl(F_GETFD) failed");
725                       }
726                       else
727                       {
728                           sock_flags |= FD_CLOEXEC;
729                           if (fcntl(socket, F_SETFD, sock_flags) < 0)
730                           {
731 marek       1.95              PEG_TRACE_CSTRING(TRC_DISCARDED_DATA, Tracer::LEVEL2,
732 kumpf       1.92                  "HTTPAcceptor: fcntl(F_SETFD) failed");
733                           }
734                       }
735 karl        1.91  #endif
736                   
737                   
738 kumpf       1.92      PEG_LOGGER_TRACE((Logger::STANDARD_LOG, System::CIMSERVER, 0,
739                           "HTTPAcceptor - accept() success.  Socket: $1" ,socket));
740                   
741 kumpf       1.96      SharedPtr<MP_Socket> mp_socket(new MP_Socket(
742 sushma.fernandes 1.97          socket, _sslcontext, _sslContextObjectLock, ipAddress));
743 kumpf            1.92  
744                            mp_socket->setSocketWriteTimeout(_socketWriteTimeout);
745                        
746                            // Perform the SSL handshake, if applicable.  Make the socket non-blocking
747                            // for this operation so we can send it back to the Monitor's select() loop
748                            // if it takes a while.
749                        
750                            mp_socket->disableBlocking();
751                            Sint32 socketAcceptStatus = mp_socket->accept();
752                            mp_socket->enableBlocking();
753                        
754                            if (socketAcceptStatus < 0)
755                            {
756 marek            1.95          PEG_TRACE_CSTRING(TRC_DISCARDED_DATA, Tracer::LEVEL2,
757 kumpf            1.92              "HTTPAcceptor: SSL_accept() failed");
758                                mp_socket->close();
759                                return;
760                            }
761                        
762                            // Create a new connection and add it to the connection list:
763                        
764                            HTTPConnection* connection = new HTTPConnection(_monitor, mp_socket,
765                                ipAddress, this, static_cast<MessageQueue *>(_outputMessageQueue));
766                        
767                            if (socketAcceptStatus == 0)
768                            {
769 marek            1.95          PEG_TRACE_CSTRING(TRC_HTTP, Tracer::LEVEL2,
770 kumpf            1.92              "HTTPAcceptor: SSL_accept() pending");
771                                connection->_acceptPending = true;
772                            }
773 karl             1.91  
774 kumpf            1.92      // Solicit events on this new connection's socket:
775                            int index;
776 karl             1.91  
777 kumpf            1.92      if (-1 ==  (index = _monitor->solicitSocketMessages(
778                                    connection->getSocket(),
779                                    SocketMessage::READ | SocketMessage::EXCEPTION,
780                                    connection->getQueueId(), Monitor::CONNECTION)) )
781                            {
782                                // ATTN-DE-P2-2003100503::TODO::Need to enhance code to return
783                                // an error message to Client application.
784 marek            1.95          PEG_TRACE_CSTRING(TRC_DISCARDED_DATA, Tracer::LEVEL2,
785 kumpf            1.92              "HTTPAcceptor::_acceptConnection: Attempt to allocate entry in "
786                                        "_entries table failed.");
787                                delete connection;
788                                Socket::close(socket);
789                                return;
790                            }
791 karl             1.91  
792 kumpf            1.92      // Save the socket for cleanup later:
793                            connection->_entry_index = index;
794                            AutoMutex autoMut(_rep->_connection_mut);
795                            _rep->connections.append(connection);
796 karl             1.91  }
797                        
798 kumpf            1.92  PEGASUS_NAMESPACE_END

No CVS admin address has been configured
Powered by
ViewCVS 0.9.2