(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 dave.sudlik 1.101 #include "HostAddress.h"
 44 karl        1.91  #include "Tracer.h"
 45 kumpf       1.93  #include <Pegasus/Common/MessageLoader.h>
 46 karl        1.91  
 47 ouyang.jian 1.102 #ifdef PEGASUS_OS_PASE
 48                   # include <as400_protos.h>
 49                   # include <Pegasus/Common/PaseCcsid.h>
 50                   #endif
 51                   
 52 karl        1.91  PEGASUS_USING_STD;
 53                   
 54                   PEGASUS_NAMESPACE_BEGIN
 55                   
 56                   
 57 mateus.baur 1.103 static int _maxConnectionQueueLength = -1;
 58 karl        1.91  
 59                   ////////////////////////////////////////////////////////////////////////////////
 60                   //
 61                   // HTTPAcceptorRep
 62                   //
 63                   ////////////////////////////////////////////////////////////////////////////////
 64                   
 65                   class HTTPAcceptorRep
 66                   {
 67                   public:
 68 dave.sudlik 1.101     HTTPAcceptorRep(Uint16 connectionType)
 69 karl        1.91      {
 70 dave.sudlik 1.101         if (connectionType == HTTPAcceptor::LOCAL_CONNECTION)
 71 karl        1.91          {
 72                   #ifndef PEGASUS_DISABLE_LOCAL_DOMAIN_SOCKET
 73 kumpf       1.92              address =
 74                                   reinterpret_cast<struct sockaddr*>(new struct sockaddr_un);
 75 karl        1.91              address_size = sizeof(struct sockaddr_un);
 76                   #else
 77                               PEGASUS_ASSERT(false);
 78                   #endif
 79                           }
 80 dave.sudlik 1.101 #ifdef PEGASUS_ENABLE_IPV6
 81                           else if (connectionType == HTTPAcceptor::IPV6_CONNECTION)
 82                           {
 83                               address =
 84                                   reinterpret_cast<struct sockaddr*>(new struct sockaddr_in6);
 85                               address_size = sizeof(struct sockaddr_in6);
 86                           }
 87                   #endif
 88                           else if (connectionType == HTTPAcceptor::IPV4_CONNECTION)
 89 karl        1.91          {
 90 kumpf       1.92              address =
 91                                   reinterpret_cast<struct sockaddr*>(new struct sockaddr_in);
 92 karl        1.91              address_size = sizeof(struct sockaddr_in);
 93                           }
 94 dave.sudlik 1.101         else
 95                           {
 96                               PEGASUS_ASSERT(false);
 97 karl        1.91      }
 98 dave.sudlik 1.101     }
 99                   
100 karl        1.91      ~HTTPAcceptorRep()
101                       {
102 kumpf       1.116         closeSocket();
103 karl        1.91          delete address;
104                       }
105 kumpf       1.116 
106                       void closeSocket()
107                       {
108                           Socket::close(socket);
109                       }
110                   
111 karl        1.91      struct sockaddr* address;
112                   
113                       SocketLength address_size;
114                       Mutex _connection_mut;
115                   
116                       SocketHandle socket;
117                       Array<HTTPConnection*> connections;
118                   };
119                   
120                   
121                   ////////////////////////////////////////////////////////////////////////////////
122                   //
123                   // HTTPAcceptor
124                   //
125                   ////////////////////////////////////////////////////////////////////////////////
126                   
127                   HTTPAcceptor::HTTPAcceptor(Monitor* monitor,
128                                              MessageQueue* outputMessageQueue,
129 dave.sudlik 1.101                            Uint16 connectionType,
130 karl        1.91                             Uint32 portNumber,
131                                              SSLContext * sslcontext,
132                                              ReadWriteSem* sslContextObjectLock)
133                      : Base(PEGASUS_QUEUENAME_HTTPACCEPTOR),  // ATTN: Need unique names?
134                        _monitor(monitor),
135                        _outputMessageQueue(outputMessageQueue),
136                        _rep(0),
137                        _entry_index(-1),
138 dave.sudlik 1.101      _connectionType(connectionType),
139 karl        1.91       _portNumber(portNumber),
140                        _sslcontext(sslcontext),
141 dave.sudlik 1.108      _sslContextObjectLock(sslContextObjectLock),
142                        _idleConnectionTimeoutSeconds(0)
143 karl        1.91  {
144                      Socket::initializeInterface();
145                   
146                      /*
147 mateus.baur 1.103         Platforms interpret the value of _maxConnectionQueueLength
148 kumpf       1.92          differently.  Some platforms interpret the value literally, while
149                           others multiply a fudge factor. When the server is under stress from
150                           multiple clients with multiple requests, toggling this number may
151                           prevent clients from being dropped.  Instead of hard coding the
152                           value, we allow an environment variable to be set which specifies a
153                           number greater than the maximum concurrent client connections
154                           possible.  If this environment var is not specified, then
155 mateus.baur 1.103         _maxConnectionQueueLength = 15.
156 karl        1.91     */
157                   
158 kumpf       1.92  //To engage runtime backlog queue length: uncomment the following block AND
159 mateus.baur 1.103 //comment out the line _maxConnectionQueueLength = 15
160 karl        1.91  
161                   /*
162 mateus.baur 1.103     if (_maxConnectionQueueLength == -1)
163 kumpf       1.92      {
164                           const char* env = getenv("PEGASUS_MAX_BACKLOG_CONNECTION_QUEUE");
165                           if (!env)
166                           {
167 mateus.baur 1.103             _maxConnectionQueueLength = 15;
168 kumpf       1.92          }
169                           else
170                           {
171                               char* end = NULL;
172 mateus.baur 1.103             _maxConnectionQueueLength = strtol(env, &end, 10);
173 kumpf       1.92              if (*end)
174 mateus.baur 1.103                 _maxConnectionQueueLength = 15;
175                               cout << " _maxConnectionQueueLength = " <<
176                                   _maxConnectionQueueLength << endl;
177 kumpf       1.92          }
178 karl        1.91      }
179                   */
180 mateus.baur 1.103 #ifdef PEGASUS_WMIMAPPER
181                       //The WMI Mapper can be used as a proxy to multiple WMI Servers.
182                       //If a client application simultaneously initiates connections
183                       //to many Windows systems, many of these connections may be routed
184                       //to a single WMI Mapper. A larger _maxConnectionQueueLength
185                       //value is required to allow these connections to be initiated
186                       //successfully.
187                       _maxConnectionQueueLength = 40;
188                   #else
189                       _maxConnectionQueueLength = 15;
190                   #endif
191 karl        1.91  }
192                   
193                   HTTPAcceptor::~HTTPAcceptor()
194                   {
195 kumpf       1.92      destroyConnections();
196                       unbind();
197                       // ATTN: Is this correct in a multi-HTTPAcceptor server?
198                       Socket::uninitializeInterface();
199 karl        1.91  }
200                   
201                   void HTTPAcceptor::handleEnqueue(Message *message)
202                   {
203 kumpf       1.92      if (!message)
204                          return;
205                   
206                       PEGASUS_ASSERT(_rep != 0);
207                       switch (message->getType())
208                       {
209                           case SOCKET_MESSAGE:
210                           {
211                               SocketMessage* socketMessage = (SocketMessage*)message;
212                   
213                               // If this is a connection request:
214                   
215                               if (socketMessage->socket == _rep->socket &&
216                                   socketMessage->events & SocketMessage::READ)
217                               {
218                                   _acceptConnection();
219                               }
220                               else
221                               {
222                                   // ATTN! this can't happen!
223 marek       1.95                  PEG_TRACE_CSTRING(TRC_DISCARDED_DATA, Tracer::LEVEL2,
224 kumpf       1.92                      "HTTPAcceptor::handleEnqueue: Invalid SOCKET_MESSAGE "
225                                           "received.");
226                              }
227 karl        1.91  
228                              break;
229 kumpf       1.92         }
230                   
231                          case CLOSE_CONNECTION_MESSAGE:
232                          {
233                              CloseConnectionMessage* closeConnectionMessage =
234                                  (CloseConnectionMessage*)message;
235                   
236                              AutoMutex autoMut(_rep->_connection_mut);
237                   
238                              for (Uint32 i = 0, n = _rep->connections.size(); i < n; i++)
239                              {
240                                  HTTPConnection* connection = _rep->connections[i];
241                                  SocketHandle socket = connection->getSocket();
242                   
243                                  if (socket == closeConnectionMessage->socket)
244                                  {
245                                      _monitor->unsolicitSocketMessages(socket);
246                                      _rep->connections.remove(i);
247                                      delete connection;
248                                      break;
249                                  }
250 kumpf       1.92             }
251 karl        1.91  
252 kumpf       1.92             break;
253                          }
254 karl        1.91  
255 kumpf       1.92         default:
256                              // ATTN: need unexpected message error!
257 marek       1.95             PEG_TRACE_CSTRING(TRC_DISCARDED_DATA, Tracer::LEVEL2,
258 kumpf       1.92                 "HTTPAcceptor::handleEnqueue: Invalid MESSAGE received.");
259                              break;
260                       }
261 karl        1.91  
262 kumpf       1.92      delete message;
263 karl        1.91  }
264                   
265                   
266                   void HTTPAcceptor::handleEnqueue()
267                   {
268 kumpf       1.92      Message* message = dequeue();
269 karl        1.91  
270 kumpf       1.92      if (!message)
271                       {
272 marek       1.95          PEG_TRACE_CSTRING(TRC_DISCARDED_DATA, Tracer::LEVEL2,
273 kumpf       1.92              "HTTPAcceptor::handleEnqueue(): No message on queue.");
274                           return;
275                       }
276 karl        1.91  
277 kumpf       1.92      handleEnqueue(message);
278 karl        1.91  }
279                   
280                   void HTTPAcceptor::bind()
281                   {
282 kumpf       1.92      if (_rep)
283                       {
284                           MessageLoaderParms parms("Common.HTTPAcceptor.ALREADY_BOUND",
285                               "HTTPAcceptor already bound");
286 karl        1.91  
287 marek       1.95          PEG_TRACE_CSTRING(TRC_DISCARDED_DATA, Tracer::LEVEL2,
288 kumpf       1.92              "HTTPAcceptor::bind: HTTPAcceptor already bound.");
289                           throw BindFailedException(parms);
290                       }
291 karl        1.91  
292 dave.sudlik 1.101     _rep = new HTTPAcceptorRep(_connectionType);
293 karl        1.91  
294 kumpf       1.92      // bind address
295                       _bind();
296 karl        1.91  }
297                   
298                   /**
299 kumpf       1.92      _bind - creates a new server socket and bind socket to the port address.
300                       If PEGASUS_DISABLE_LOCAL_DOMAIN_SOCKET is not defined, the port number is
301                       ignored and a domain socket is bound.
302 karl        1.91  */
303                   void HTTPAcceptor::_bind()
304                   {
305 ouyang.jian 1.102 #ifdef PEGASUS_OS_PASE
306                       // bind need ccsid is 819 
307                       int orig_ccsid;
308                       orig_ccsid = _SETCCSID(-1);
309                       if (orig_ccsid == -1)
310                       {
311                           PEG_TRACE_STRING(TRC_DISCARDED_DATA, Tracer::LEVEL2,
312                               String("HTTPAcceptor::_bind: Can not get current PASE CCSID."));
313                           orig_ccsid = 1208;
314                       }
315                       PaseCcsid ccsid(819, orig_ccsid);
316                   #endif
317                   
318 kumpf       1.92      PEGASUS_ASSERT(_rep != 0);
319                       // Create address:
320 dave.sudlik 1.101     memset(_rep->address, 0, _rep->address_size);
321 karl        1.91  
322 dave.sudlik 1.101     if (_connectionType == LOCAL_CONNECTION)
323 kumpf       1.92      {
324 karl        1.91  #ifndef PEGASUS_DISABLE_LOCAL_DOMAIN_SOCKET
325 kumpf       1.100         //
326                           // Make sure the local domain socket can be owned by the cimserver
327                           // user.  Otherwise, the bind may fail with a vague "bind failed"
328                           // error.
329                           //
330                           if (System::exists(PEGASUS_LOCAL_DOMAIN_SOCKET_PATH))
331                           {
332                               if (!System::removeFile(PEGASUS_LOCAL_DOMAIN_SOCKET_PATH))
333                               {
334                                   throw CannotRemoveFile(PEGASUS_LOCAL_DOMAIN_SOCKET_PATH);
335                               }
336                           }
337                   
338 kumpf       1.92          reinterpret_cast<struct sockaddr_un*>(_rep->address)->sun_family =
339                               AF_UNIX;
340                           strcpy(reinterpret_cast<struct sockaddr_un*>(_rep->address)->sun_path,
341                               PEGASUS_LOCAL_DOMAIN_SOCKET_PATH);
342 karl        1.91  #else
343 kumpf       1.92          PEGASUS_ASSERT(false);
344 karl        1.91  #endif
345 kumpf       1.92      }
346 dave.sudlik 1.101 #ifdef PEGASUS_ENABLE_IPV6
347                       else if (_connectionType == IPV6_CONNECTION)
348                       {
349                           reinterpret_cast<struct sockaddr_in6*>(_rep->address)->sin6_addr =
350                               in6addr_any;
351                           reinterpret_cast<struct sockaddr_in6*>(_rep->address)->sin6_family =
352                               AF_INET6;
353                           reinterpret_cast<struct sockaddr_in6*>(_rep->address)->sin6_port =
354                               htons(_portNumber);
355                       }
356                   #endif
357                       else if(_connectionType == IPV4_CONNECTION)
358 kumpf       1.92      {
359                           reinterpret_cast<struct sockaddr_in*>(_rep->address)->sin_addr.s_addr =
360                               INADDR_ANY;
361                           reinterpret_cast<struct sockaddr_in*>(_rep->address)->sin_family =
362                               AF_INET;
363                           reinterpret_cast<struct sockaddr_in*>(_rep->address)->sin_port =
364                               htons(_portNumber);
365                       }
366 dave.sudlik 1.101     else
367                       {
368                           PEGASUS_ASSERT(false);
369                       }
370 kumpf       1.92  
371                       // Create socket:
372                   
373 dave.sudlik 1.101     if (_connectionType == LOCAL_CONNECTION)
374 kumpf       1.92      {
375                           _rep->socket = Socket::createSocket(AF_UNIX, SOCK_STREAM, 0);
376                       }
377 dave.sudlik 1.101 #ifdef PEGASUS_ENABLE_IPV6
378                       else if (_connectionType == IPV6_CONNECTION)
379                       {
380                           _rep->socket = Socket::createSocket(PF_INET6, SOCK_STREAM, IPPROTO_TCP);
381                       }
382                   #endif
383                       else if (_connectionType == IPV4_CONNECTION)
384                       {
385                           _rep->socket = Socket::createSocket(PF_INET, SOCK_STREAM, IPPROTO_TCP);
386                       }
387 kumpf       1.92      else
388                       {
389 dave.sudlik 1.101         PEGASUS_ASSERT(false);
390 kumpf       1.92      }
391                   
392                       if (_rep->socket < 0)
393                       {
394                           delete _rep;
395                           _rep = 0;
396                           MessageLoaderParms parms("Common.HTTPAcceptor.FAILED_CREATE_SOCKET",
397                               "Failed to create socket");
398 marek       1.95          PEG_TRACE_CSTRING(TRC_DISCARDED_DATA, Tracer::LEVEL2,
399 thilo.boehm 1.115             "HTTPAcceptor::_bind:  createSocket() _rep->socket failed");
400 kumpf       1.92          throw BindFailedException(parms);
401                       }
402 karl        1.91  
403 kumpf       1.109     Socket::disableBlocking(_rep->socket);
404 karl        1.91  
405                   // set the close-on-exec bit for this file handle.
406                   // any unix that forks needs this bit set.
407                   #if !defined PEGASUS_OS_TYPE_WINDOWS && !defined(PEGASUS_OS_VMS)
408 kumpf       1.92      int sock_flags;
409                       if ((sock_flags = fcntl(_rep->socket, F_GETFD, 0)) < 0)
410                       {
411 marek       1.95          PEG_TRACE_CSTRING(TRC_DISCARDED_DATA, Tracer::LEVEL2,
412 kumpf       1.92              "HTTPAcceptor::_bind: fcntl(F_GETFD) failed");
413                       }
414                       else
415                       {
416                           sock_flags |= FD_CLOEXEC;
417                           if (fcntl(_rep->socket, F_SETFD, sock_flags) < 0)
418                           {
419 marek       1.95              PEG_TRACE_CSTRING(TRC_DISCARDED_DATA, Tracer::LEVEL2,
420 kumpf       1.92                  "HTTPAcceptor::_bind: fcntl(F_SETFD) failed");
421                           }
422                       }
423                   #endif
424                   
425                   
426                       //
427                       // Set the socket option SO_REUSEADDR to reuse the socket address so
428                       // that we can rebind to a new socket using the same address when we
429                       // need to resume the cimom as a result of a timeout during a Shutdown
430                       // operation.
431                       //
432                       int opt=1;
433                       if (setsockopt(_rep->socket, SOL_SOCKET, SO_REUSEADDR,
434                               (char *)&opt, sizeof(opt)) < 0)
435                       {
436                           delete _rep;
437                           _rep = 0;
438                           MessageLoaderParms parms("Common.HTTPAcceptor.FAILED_SET_SOCKET_OPTION",
439                               "Failed to set socket option");
440 marek       1.95          PEG_TRACE_CSTRING(TRC_DISCARDED_DATA, Tracer::LEVEL2,
441 kumpf       1.92              "HTTPAcceptor::_bind: Failed to set socket option.");
442                           throw BindFailedException(parms);
443                       }
444                   
445                   
446                       //
447                       // Bind socket to port:
448                       //
449                       if (::bind(_rep->socket, _rep->address, _rep->address_size) < 0)
450                       {
451 thilo.boehm 1.115         MessageLoaderParms parms(
452                               "Common.HTTPAcceptor.FAILED_BIND_SOCKET_DETAIL",
453                               "Failed to bind socket on port $0: $1.",
454                               _portNumber, PEGASUS_SYSTEM_NETWORK_ERRORMSG_NLS);
455                   
456 kumpf       1.92          delete _rep;
457                           _rep = 0;
458 marek       1.95          PEG_TRACE_CSTRING(TRC_DISCARDED_DATA, Tracer::LEVEL2,
459 kumpf       1.92              "HTTPAcceptor::_bind: Failed to bind socket.");
460                           throw BindFailedException(parms);
461                       }
462                   
463                   
464                       //
465                       // Get the actual port value used if the caller specified a port value of 0.
466                       //
467                       if (_portNumber == 0)
468                       {
469                           sockaddr_in buf;
470                           SocketLength bufSize = sizeof(buf);
471                           if (getsockname(_rep->socket, reinterpret_cast<sockaddr *>(&buf),
472                                   &bufSize) == 0 )
473                           {
474                               _portNumber = ntohs(buf.sin_port);
475                           }
476                       }
477                   
478                   
479                       //
480 kumpf       1.92      // Change permissions on Linux local domain socket to allow writes by
481                       // others.
482                       //
483 karl        1.91  #if !defined(PEGASUS_DISABLE_LOCAL_DOMAIN_SOCKET) && \
484 kumpf       1.92       (defined(PEGASUS_PLATFORM_LINUX_GENERIC_GNU) || \
485                         defined(PEGASUS_PLATFORM_ZOS_ZSERIES_IBM))
486 dave.sudlik 1.101     if (_connectionType == LOCAL_CONNECTION)
487 kumpf       1.92      {
488                           if (::chmod(PEGASUS_LOCAL_DOMAIN_SOCKET_PATH,
489                                   S_IRUSR | S_IWUSR | S_IXUSR |
490                                   S_IRGRP | S_IWGRP | S_IXGRP |
491                                   S_IROTH | S_IWOTH | S_IXOTH ) < 0 )
492                           {
493 thilo.boehm 1.115             MessageLoaderParms parms(
494                                   "Common.HTTPAcceptor.FAILED_SET_LDS_FILE_OPTION",
495                                   "Failed to set permission on local domain socket {0}: {1}.",
496                                   PEGASUS_LOCAL_DOMAIN_SOCKET_PATH,
497                                   PEGASUS_SYSTEM_ERRORMSG_NLS );
498                   
499 kumpf       1.92              delete _rep;
500                               _rep = 0;
501 marek       1.95              PEG_TRACE_CSTRING(TRC_DISCARDED_DATA, Tracer::LEVEL2,
502 kumpf       1.92                  "HTTPAcceptor::_bind: Failed to set domain socket "
503                                       "permissions.");
504                               throw BindFailedException(parms);
505                           }
506                       }
507                   #endif
508                   
509                       // Set up listening on the given socket:
510                   
511 mateus.baur 1.103     //int const _maxConnectionQueueLength = 15;
512 kumpf       1.92  
513 thilo.boehm 1.115     if (::listen(_rep->socket, _maxConnectionQueueLength) < 0)
514 kumpf       1.92      {
515 thilo.boehm 1.115         MessageLoaderParms parms(
516                               "Common.HTTPAcceptor.FAILED_LISTEN_SOCKET",
517                               "Failed to listen on socket {0}: {1}.",
518                               (int)_rep->socket,PEGASUS_SYSTEM_NETWORK_ERRORMSG_NLS );
519                           
520 kumpf       1.92          delete _rep;
521                           _rep = 0;
522 marek       1.95          PEG_TRACE_CSTRING(TRC_DISCARDED_DATA, Tracer::LEVEL2,
523 kumpf       1.92              "HTTPAcceptor::_bind: Failed to bind socket(1).");
524                           throw BindFailedException(parms);
525                       }
526                   
527                       // Register to receive SocketMessages on this socket:
528                   
529                       if (-1 == ( _entry_index = _monitor->solicitSocketMessages(
530                               _rep->socket,
531                               SocketMessage::READ | SocketMessage::EXCEPTION,
532                               getQueueId(),
533 kumpf       1.107             MonitorEntry::TYPE_ACCEPTOR)))
534 kumpf       1.92      {
535                           delete _rep;
536                           _rep = 0;
537                           MessageLoaderParms parms(
538                               "Common.HTTPAcceptor.FAILED_SOLICIT_SOCKET_MESSAGES",
539                               "Failed to solicit socket messaeges");
540 marek       1.95          PEG_TRACE_CSTRING(TRC_DISCARDED_DATA, Tracer::LEVEL2,
541 kumpf       1.92              "HTTPAcceptor::_bind: Failed to solicit socket messages(2).");
542                           throw BindFailedException(parms);
543                       }
544 karl        1.91  }
545                   
546                   /**
547 kumpf       1.92      closeConnectionSocket - close the server listening socket to disallow
548                       new client connections.
549 karl        1.91  */
550                   void HTTPAcceptor::closeConnectionSocket()
551                   {
552 kumpf       1.92      if (_rep)
553                       {
554                           // unregister the socket
555                   
556                           // ATTN - comment out - see CIMServer::stopClientConnection()
557                           //_monitor->unsolicitSocketMessages(_rep->socket);
558                   
559                           // close the socket
560 kumpf       1.116         _rep->closeSocket();
561 kumpf       1.92          // Unlink Local Domain Socket Bug# 3312
562 dave.sudlik 1.101         if (_connectionType == LOCAL_CONNECTION)
563 kumpf       1.92          {
564 karl        1.91  #ifndef PEGASUS_DISABLE_LOCAL_DOMAIN_SOCKET
565 marek       1.95              PEG_TRACE_CSTRING(TRC_HTTP, Tracer::LEVEL2,
566 kumpf       1.92                  "HTTPAcceptor::closeConnectionSocket Unlinking local "
567                                       "connection.");
568                               ::unlink(
569                                   reinterpret_cast<struct sockaddr_un*>(_rep->address)->sun_path);
570 karl        1.91  #else
571 kumpf       1.92              PEGASUS_ASSERT(false);
572 karl        1.91  #endif
573 kumpf       1.92          }
574                       }
575                       else
576                       {
577 marek       1.95          PEG_TRACE_CSTRING(TRC_DISCARDED_DATA, Tracer::LEVEL2,
578 kumpf       1.92              "HTTPAcceptor::closeConnectionSocket failure _rep is null.");
579                       }
580 karl        1.91  }
581                   
582                   /**
583                      reopenConnectionSocket - creates a new server socket.
584                   */
585                   void HTTPAcceptor::reopenConnectionSocket()
586                   {
587 kumpf       1.92      if (_rep)
588                       {
589                           _bind();
590                       }
591                       else
592                       {
593 marek       1.95          PEG_TRACE_CSTRING(TRC_DISCARDED_DATA, Tracer::LEVEL2,
594 kumpf       1.92              "HTTPAcceptor::reopenConnectionSocket failure _rep is null.");
595                       }
596 karl        1.91  }
597                   
598                   
599                   /**
600                      reconnectConnectionSocket - creates a new server socket.
601                   */
602                   void HTTPAcceptor::reconnectConnectionSocket()
603                   {
604 kumpf       1.92      if (_rep)
605                       {
606                           // unregister the socket
607                           _monitor->unsolicitSocketMessages(_rep->socket);
608                           // close the socket
609 kumpf       1.116         _rep->closeSocket();
610                           // Unlink Local Domain Socket
611 dave.sudlik 1.101         if (_connectionType == LOCAL_CONNECTION)
612 kumpf       1.92          {
613 karl        1.91  #ifndef PEGASUS_DISABLE_LOCAL_DOMAIN_SOCKET
614 marek       1.95              PEG_TRACE_CSTRING(TRC_HTTP, Tracer::LEVEL2,
615 kumpf       1.92                  "HTTPAcceptor::reconnectConnectionSocket Unlinking local "
616                                       "connection." );
617                               ::unlink(
618                                   reinterpret_cast<struct sockaddr_un*>(_rep->address)->sun_path);
619 karl        1.91  #else
620 kumpf       1.92              PEGASUS_ASSERT(false);
621 karl        1.91  #endif
622 kumpf       1.92          }
623                           // open the socket
624                           _bind();
625                       }
626                       else
627                       {
628 marek       1.95          PEG_TRACE_CSTRING(TRC_DISCARDED_DATA, Tracer::LEVEL2,
629 kumpf       1.92              "HTTPAcceptor::reconnectConnectionSocket failure _rep is null.");
630                       }
631 karl        1.91  }
632                   
633                   /**
634 kumpf       1.92      getOutstandingRequestCount - returns the number of outstanding requests.
635 karl        1.91  */
636                   Uint32 HTTPAcceptor::getOutstandingRequestCount() const
637                   {
638 kumpf       1.92      Uint32 count = 0;
639                       if (_rep)
640                       {
641                           AutoMutex autoMut(_rep->_connection_mut);
642 kumpf       1.110         for (Uint32 i = 0, n = _rep->connections.size(); i < n; i++)
643 kumpf       1.92          {
644 kumpf       1.110             HTTPConnection* connection = _rep->connections[i];
645                               if (connection->isResponsePending())
646                               {
647                                   count++;
648                               }
649 kumpf       1.92          }
650                       }
651                       return count;
652 karl        1.91  }
653                   
654                   
655                   /**
656                       getPortNumber - returns the port number used for the connection
657                   */
658                   Uint32 HTTPAcceptor::getPortNumber() const
659                   {
660                       return _portNumber;
661                   }
662                   
663                   void HTTPAcceptor::setSocketWriteTimeout(Uint32 socketWriteTimeout)
664                   {
665                       _socketWriteTimeout = socketWriteTimeout;
666                   }
667                   
668 dave.sudlik 1.108 void HTTPAcceptor::setIdleConnectionTimeout(Uint32 idleConnectionTimeoutSeconds)
669                   {
670                       _idleConnectionTimeoutSeconds = idleConnectionTimeoutSeconds;
671                   }
672                   
673 karl        1.91  void HTTPAcceptor::unbind()
674                   {
675 kumpf       1.92      if (_rep)
676                       {
677                           _portNumber = 0;
678 kumpf       1.116         _rep->closeSocket();
679 karl        1.91  
680 dave.sudlik 1.101         if (_connectionType == LOCAL_CONNECTION)
681 kumpf       1.92          {
682 karl        1.91  #ifndef PEGASUS_DISABLE_LOCAL_DOMAIN_SOCKET
683 kumpf       1.92              ::unlink(
684                                   reinterpret_cast<struct sockaddr_un*>(_rep->address)->sun_path);
685 karl        1.91  #else
686 kumpf       1.92              PEGASUS_ASSERT(false);
687 karl        1.91  #endif
688 kumpf       1.92          }
689 karl        1.91  
690 kumpf       1.92          delete _rep;
691                           _rep = 0;
692                       }
693                       else
694                       {
695 marek       1.95          PEG_TRACE_CSTRING(TRC_DISCARDED_DATA, Tracer::LEVEL2,
696 kumpf       1.92              "HTTPAcceptor::unbind failure _rep is null." );
697                       }
698 karl        1.91  }
699                   
700                   void HTTPAcceptor::destroyConnections()
701                   {
702 kumpf       1.92      if (_rep)
703                       {
704                           // For each connection created by this object:
705 karl        1.91  
706 kumpf       1.92          AutoMutex autoMut(_rep->_connection_mut);
707                           for (Uint32 i = 0, n = _rep->connections.size(); i < n; i++)
708                           {
709                               HTTPConnection* connection = _rep->connections[i];
710                               SocketHandle socket = connection->getSocket();
711 karl        1.91  
712 kumpf       1.92              // Unsolicit SocketMessages:
713 karl        1.91  
714 kumpf       1.92              _monitor->unsolicitSocketMessages(socket);
715 karl        1.91  
716 kumpf       1.92              // Destroy the connection (causing it to close):
717 karl        1.91  
718 kumpf       1.92              while (connection->refcount.get()) { }
719                               delete connection;
720                           }
721 karl        1.91  
722 kumpf       1.92          _rep->connections.clear();
723                       }
724 karl        1.91  }
725                   
726                   void HTTPAcceptor::_acceptConnection()
727                   {
728 kumpf       1.92      // This function cannot be called on an invalid socket!
729 karl        1.91  
730 kumpf       1.92      PEGASUS_ASSERT(_rep != 0);
731 karl        1.91  
732 kumpf       1.92      // Accept the connection (populate the address):
733 karl        1.91  
734 kumpf       1.92      struct sockaddr* accept_address;
735                       SocketLength address_size;
736 karl        1.91  
737 dave.sudlik 1.101     if (_connectionType == LOCAL_CONNECTION)
738 kumpf       1.92      {
739 karl        1.91  #ifndef PEGASUS_DISABLE_LOCAL_DOMAIN_SOCKET
740 kumpf       1.92          accept_address =
741                               reinterpret_cast<struct sockaddr*>(new struct sockaddr_un);
742                           address_size = sizeof(struct sockaddr_un);
743 karl        1.91  #else
744 kumpf       1.92          PEGASUS_ASSERT(false);
745 karl        1.91  #endif
746 kumpf       1.92      }
747                       else
748                       {
749 dave.sudlik 1.101 #ifdef PEGASUS_ENABLE_IPV6
750                           accept_address =
751                              reinterpret_cast<struct sockaddr*>
752                              (new struct sockaddr_storage);
753                           address_size = sizeof(struct sockaddr_storage);
754                   #else
755 kumpf       1.92          accept_address =
756                               reinterpret_cast<struct sockaddr*>(new struct sockaddr_in);
757                           address_size = sizeof(struct sockaddr_in);
758 dave.sudlik 1.101 #endif
759 kumpf       1.92      }
760                   
761 kumpf       1.109     // It is not necessary to handle EINTR errors from this accept() call.
762                       // An EINTR error should not occur on a non-blocking socket.  If the
763                       // listen socket is blocking and EINTR occurs, the new socket connection
764                       // is not accepted here.
765                   
766                       // EAGAIN errors are also not handled here.  An EAGAIN error should not
767                       // occur after select() indicates that the listen socket is available for
768                       // reading.  If the accept() fails with an EAGAIN error code, a new
769                       // connection is not accepted here.
770                   
771                       SocketHandle socket = accept(_rep->socket, accept_address, &address_size);
772 kumpf       1.92  
773                       if (socket == PEGASUS_SOCKET_ERROR)
774                       {
775                           // the remote connection is invalid, destroy client address.
776                           delete accept_address;
777                   
778                           // TCPIP is down reconnect this acceptor
779                           if (getSocketError() == PEGASUS_NETWORK_TCPIP_STOPPED)
780                           {
781 marek       1.95              PEG_TRACE_CSTRING(TRC_DISCARDED_DATA, Tracer::LEVEL2,
782 kumpf       1.92                  "Socket has an IO error. TCP/IP down. Try to reconnect.");
783                   
784                               reconnectConnectionSocket();
785                   
786                               return;
787                           }
788 karl        1.91  
789 kumpf       1.92          Logger::put(Logger::STANDARD_LOG, System::CIMSERVER, Logger::TRACE,
790                               "HTTPAcceptor - accept() failure.  errno: $0", errno);
791 karl        1.91  
792 marek       1.95          PEG_TRACE_CSTRING(TRC_DISCARDED_DATA, Tracer::LEVEL2,
793 kumpf       1.92              "HTTPAcceptor: accept() failed");
794                           return;
795                       }
796 kumpf       1.116 
797                       // Use an AutoPtr to ensure the socket handle is closed on exception
798                       AutoPtr<SocketHandle, CloseSocketHandle> socketPtr(&socket);
799                   
800 marek       1.114 #ifndef PEGASUS_OS_TYPE_WINDOWS
801 marek       1.111     // We need to ensure that the socket number is not higher than
802                       // what fits into FD_SETSIZE, because we else won't be able to select on it
803                       // and won't ever communicate correct on that socket.
804                       if (socket >= FD_SETSIZE)
805                       {
806                           // the remote connection is invalid, destroy client address.
807                           delete accept_address;
808                           
809                           Logger::put(Logger::STANDARD_LOG, System::CIMSERVER, Logger::TRACE,
810                               "HTTPAcceptor out of available sockets. "
811                                   "Closing connection to the new client.");
812                   
813                           PEG_TRACE(
814                               (TRC_DISCARDED_DATA,
815                                Tracer::LEVEL2,
816                                "accept() returned too large socket number %d.",
817                                socket));
818                           
819                           return;
820                       }
821 marek       1.114 #endif
822 karl        1.91  
823 kumpf       1.92      String ipAddress;
824 karl        1.91  
825 dave.sudlik 1.101     if (_connectionType == LOCAL_CONNECTION)
826 kumpf       1.92      {
827                           ipAddress = "localhost";
828                       }
829                       else
830                       {
831 dave.sudlik 1.101 #ifdef PEGASUS_ENABLE_IPV6
832                           char ipBuffer[PEGASUS_INET6_ADDRSTR_LEN];
833 dmitry.mikulin 1.105         int rc;
834 dmitry.mikulin 1.106         if ((rc = System::getNameInfo(accept_address, 
835                                      address_size, 
836                                      ipBuffer,
837                                      PEGASUS_INET6_ADDRSTR_LEN, 
838                                      0, 
839                                      0, 
840                                      NI_NUMERICHOST)))
841 dave.sudlik    1.101         {
842                                  Logger::put(Logger::STANDARD_LOG, System::CIMSERVER, Logger::TRACE,
843                                      "HTTPAcceptor - getnameinfo() failure.  rc: $0", rc);
844                      
845                                  PEG_TRACE_CSTRING(TRC_DISCARDED_DATA, Tracer::LEVEL2,
846                                      "HTTPAcceptor: getnameinfo() failed");
847                                  delete accept_address;
848                                  return;
849                              }
850                              ipAddress = ipBuffer;
851                      #else
852 kumpf          1.92          unsigned char* sa = reinterpret_cast<unsigned char*>(
853                                  &reinterpret_cast<struct sockaddr_in*>(
854                                      accept_address)->sin_addr.s_addr);
855                              char ipBuffer[32];
856                              sprintf(ipBuffer, "%u.%u.%u.%u", sa[0], sa[1], sa[2], sa[3]);
857                              ipAddress = ipBuffer;
858 dave.sudlik    1.101 #endif
859 kumpf          1.92      }
860 karl           1.91  
861 kumpf          1.92      delete accept_address;
862 karl           1.91  
863                      // set the close on exec flag
864                      #if !defined(PEGASUS_OS_TYPE_WINDOWS) && !defined(PEGASUS_OS_VMS)
865 kumpf          1.92      int sock_flags;
866                          if ((sock_flags = fcntl(socket, F_GETFD, 0)) < 0)
867                          {
868 marek          1.95          PEG_TRACE_CSTRING(TRC_DISCARDED_DATA, Tracer::LEVEL2,
869 kumpf          1.92              "HTTPAcceptor: fcntl(F_GETFD) failed");
870                          }
871                          else
872                          {
873                              sock_flags |= FD_CLOEXEC;
874                              if (fcntl(socket, F_SETFD, sock_flags) < 0)
875                              {
876 marek          1.95              PEG_TRACE_CSTRING(TRC_DISCARDED_DATA, Tracer::LEVEL2,
877 kumpf          1.92                  "HTTPAcceptor: fcntl(F_SETFD) failed");
878                              }
879                          }
880 karl           1.91  #endif
881                      
882                      
883 kumpf          1.92      PEG_LOGGER_TRACE((Logger::STANDARD_LOG, System::CIMSERVER, 0,
884                              "HTTPAcceptor - accept() success.  Socket: $1" ,socket));
885                      
886 kumpf          1.96      SharedPtr<MP_Socket> mp_socket(new MP_Socket(
887 sushma.fernandes 1.97          socket, _sslcontext, _sslContextObjectLock, ipAddress));
888 kumpf            1.116     // mp_socket now has responsibility for closing the socket handle
889                            socketPtr.release();
890 kumpf            1.92  
891 kumpf            1.109     mp_socket->disableBlocking();
892 kumpf            1.92      mp_socket->setSocketWriteTimeout(_socketWriteTimeout);
893                        
894 kumpf            1.109     // Perform the SSL handshake, if applicable.
895 kumpf            1.92  
896                            Sint32 socketAcceptStatus = mp_socket->accept();
897                        
898                            if (socketAcceptStatus < 0)
899                            {
900 marek            1.95          PEG_TRACE_CSTRING(TRC_DISCARDED_DATA, Tracer::LEVEL2,
901 kumpf            1.92              "HTTPAcceptor: SSL_accept() failed");
902                                return;
903                            }
904                        
905                            // Create a new connection and add it to the connection list:
906                        
907 kumpf            1.116     AutoPtr<HTTPConnection> connection(new HTTPConnection(
908                                _monitor,
909                                mp_socket,
910                                ipAddress,
911                                this,
912                                static_cast<MessageQueue *>(_outputMessageQueue)));
913 kumpf            1.92  
914 dave.sudlik      1.108     if (_idleConnectionTimeoutSeconds)
915                            {
916                                connection->_idleConnectionTimeoutSeconds = 
917                                    _idleConnectionTimeoutSeconds;
918                                Time::gettimeofday(&connection->_idleStartTime);
919                            }
920                        
921 kumpf            1.92      if (socketAcceptStatus == 0)
922                            {
923 marek            1.95          PEG_TRACE_CSTRING(TRC_HTTP, Tracer::LEVEL2,
924 kumpf            1.92              "HTTPAcceptor: SSL_accept() pending");
925                                connection->_acceptPending = true;
926 dave.sudlik      1.108         Time::gettimeofday(&connection->_acceptPendingStartTime);
927 kumpf            1.92      }
928 karl             1.91  
929 kumpf            1.92      // Solicit events on this new connection's socket:
930                            int index;
931 karl             1.91  
932 kumpf            1.92      if (-1 ==  (index = _monitor->solicitSocketMessages(
933                                    connection->getSocket(),
934                                    SocketMessage::READ | SocketMessage::EXCEPTION,
935 kumpf            1.107             connection->getQueueId(), MonitorEntry::TYPE_CONNECTION)) )
936 kumpf            1.92      {
937 marek            1.95          PEG_TRACE_CSTRING(TRC_DISCARDED_DATA, Tracer::LEVEL2,
938 kumpf            1.92              "HTTPAcceptor::_acceptConnection: Attempt to allocate entry in "
939                                        "_entries table failed.");
940                                return;
941                            }
942 karl             1.91  
943 kumpf            1.92      connection->_entry_index = index;
944                            AutoMutex autoMut(_rep->_connection_mut);
945 kumpf            1.116     _rep->connections.append(connection.get());
946                            connection.release();
947 karl             1.91  }
948                        
949 kumpf            1.92  PEGASUS_NAMESPACE_END

No CVS admin address has been configured
Powered by
ViewCVS 0.9.2