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

No CVS admin address has been configured
Powered by
ViewCVS 0.9.2