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

No CVS admin address has been configured
Powered by
ViewCVS 0.9.2