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

No CVS admin address has been configured
Powered by
ViewCVS 0.9.2