(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.106.2.1      _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 kumpf       1.92                  "HTTPAcceptor::_bind _rep->socket < 0");
393                               throw BindFailedException(parms);
394                           }
395 karl        1.91      
396 kumpf       1.106.2.2     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                               Socket::close(_rep->socket);
446                               delete _rep;
447                               _rep = 0;
448                               MessageLoaderParms parms("Common.HTTPAcceptor.FAILED_BIND_SOCKET",
449                                   "Failed to bind socket");
450 marek       1.95              PEG_TRACE_CSTRING(TRC_DISCARDED_DATA, Tracer::LEVEL2,
451 kumpf       1.92                  "HTTPAcceptor::_bind: Failed to bind socket.");
452                               throw BindFailedException(parms);
453                           }
454                       
455                       
456                           //
457                           // Get the actual port value used if the caller specified a port value of 0.
458                           //
459                           if (_portNumber == 0)
460                           {
461                               sockaddr_in buf;
462                               SocketLength bufSize = sizeof(buf);
463                               if (getsockname(_rep->socket, reinterpret_cast<sockaddr *>(&buf),
464                                       &bufSize) == 0 )
465                               {
466                                   _portNumber = ntohs(buf.sin_port);
467                               }
468                           }
469                       
470                       
471                           //
472 kumpf       1.92          // Change permissions on Linux local domain socket to allow writes by
473                           // others.
474                           //
475 karl        1.91      #if !defined(PEGASUS_DISABLE_LOCAL_DOMAIN_SOCKET) && \
476 kumpf       1.92           (defined(PEGASUS_PLATFORM_LINUX_GENERIC_GNU) || \
477                             defined(PEGASUS_PLATFORM_ZOS_ZSERIES_IBM))
478 dave.sudlik 1.101         if (_connectionType == LOCAL_CONNECTION)
479 kumpf       1.92          {
480                               if (::chmod(PEGASUS_LOCAL_DOMAIN_SOCKET_PATH,
481                                       S_IRUSR | S_IWUSR | S_IXUSR |
482                                       S_IRGRP | S_IWGRP | S_IXGRP |
483                                       S_IROTH | S_IWOTH | S_IXOTH ) < 0 )
484                               {
485                                   Socket::close(_rep->socket);
486                                   delete _rep;
487                                   _rep = 0;
488                                   MessageLoaderParms parms("Common.HTTPAcceptor.FAILED_BIND_SOCKET",
489                                       "Failed to bind socket");
490 marek       1.95                  PEG_TRACE_CSTRING(TRC_DISCARDED_DATA, Tracer::LEVEL2,
491 kumpf       1.92                      "HTTPAcceptor::_bind: Failed to set domain socket "
492                                           "permissions.");
493                                   throw BindFailedException(parms);
494                               }
495                           }
496                       #endif
497                       
498                           // Set up listening on the given socket:
499                       
500 mateus.baur 1.103         //int const _maxConnectionQueueLength = 15;
501 kumpf       1.92      
502 mateus.baur 1.103         if (listen(_rep->socket, _maxConnectionQueueLength) < 0)
503 kumpf       1.92          {
504                               Socket::close(_rep->socket);
505                               delete _rep;
506                               _rep = 0;
507                               MessageLoaderParms parms("Common.HTTPAcceptor.FAILED_BIND_SOCKET",
508                                   "Failed to bind socket");
509 marek       1.95              PEG_TRACE_CSTRING(TRC_DISCARDED_DATA, Tracer::LEVEL2,
510 kumpf       1.92                  "HTTPAcceptor::_bind: Failed to bind socket(1).");
511                               throw BindFailedException(parms);
512                           }
513                       
514                           // Register to receive SocketMessages on this socket:
515                       
516                           if (-1 == ( _entry_index = _monitor->solicitSocketMessages(
517                                   _rep->socket,
518                                   SocketMessage::READ | SocketMessage::EXCEPTION,
519                                   getQueueId(),
520                                   Monitor::ACCEPTOR)))
521                           {
522                               Socket::close(_rep->socket);
523                               delete _rep;
524                               _rep = 0;
525                               MessageLoaderParms parms(
526                                   "Common.HTTPAcceptor.FAILED_SOLICIT_SOCKET_MESSAGES",
527                                   "Failed to solicit socket messaeges");
528 marek       1.95              PEG_TRACE_CSTRING(TRC_DISCARDED_DATA, Tracer::LEVEL2,
529 kumpf       1.92                  "HTTPAcceptor::_bind: Failed to solicit socket messages(2).");
530                               throw BindFailedException(parms);
531                           }
532 karl        1.91      }
533                       
534                       /**
535 kumpf       1.92          closeConnectionSocket - close the server listening socket to disallow
536                           new client connections.
537 karl        1.91      */
538                       void HTTPAcceptor::closeConnectionSocket()
539                       {
540 kumpf       1.92          if (_rep)
541                           {
542                               // unregister the socket
543                       
544                               // ATTN - comment out - see CIMServer::stopClientConnection()
545                               //_monitor->unsolicitSocketMessages(_rep->socket);
546                       
547                               // close the socket
548                               Socket::close(_rep->socket);
549                               // Unlink Local Domain Socket Bug# 3312
550 dave.sudlik 1.101             if (_connectionType == LOCAL_CONNECTION)
551 kumpf       1.92              {
552 karl        1.91      #ifndef PEGASUS_DISABLE_LOCAL_DOMAIN_SOCKET
553 marek       1.95                  PEG_TRACE_CSTRING(TRC_HTTP, Tracer::LEVEL2,
554 kumpf       1.92                      "HTTPAcceptor::closeConnectionSocket Unlinking local "
555                                           "connection.");
556                                   ::unlink(
557                                       reinterpret_cast<struct sockaddr_un*>(_rep->address)->sun_path);
558 karl        1.91      #else
559 kumpf       1.92                  PEGASUS_ASSERT(false);
560 karl        1.91      #endif
561 kumpf       1.92              }
562                           }
563                           else
564                           {
565 marek       1.95              PEG_TRACE_CSTRING(TRC_DISCARDED_DATA, Tracer::LEVEL2,
566 kumpf       1.92                  "HTTPAcceptor::closeConnectionSocket failure _rep is null.");
567                           }
568 karl        1.91      }
569                       
570                       /**
571                          reopenConnectionSocket - creates a new server socket.
572                       */
573                       void HTTPAcceptor::reopenConnectionSocket()
574                       {
575 kumpf       1.92          if (_rep)
576                           {
577                               _bind();
578                           }
579                           else
580                           {
581 marek       1.95              PEG_TRACE_CSTRING(TRC_DISCARDED_DATA, Tracer::LEVEL2,
582 kumpf       1.92                  "HTTPAcceptor::reopenConnectionSocket failure _rep is null.");
583                           }
584 karl        1.91      }
585                       
586                       
587                       /**
588                          reconnectConnectionSocket - creates a new server socket.
589                       */
590                       void HTTPAcceptor::reconnectConnectionSocket()
591                       {
592 kumpf       1.92          if (_rep)
593                           {
594                               // unregister the socket
595                               _monitor->unsolicitSocketMessages(_rep->socket);
596                               // close the socket
597                               Socket::close(_rep->socket);
598                               // Unlink Local Domain Socket Bug# 3312
599 dave.sudlik 1.101             if (_connectionType == LOCAL_CONNECTION)
600 kumpf       1.92              {
601 karl        1.91      #ifndef PEGASUS_DISABLE_LOCAL_DOMAIN_SOCKET
602 marek       1.95                  PEG_TRACE_CSTRING(TRC_HTTP, Tracer::LEVEL2,
603 kumpf       1.92                      "HTTPAcceptor::reconnectConnectionSocket Unlinking local "
604                                           "connection." );
605                                   ::unlink(
606                                       reinterpret_cast<struct sockaddr_un*>(_rep->address)->sun_path);
607 karl        1.91      #else
608 kumpf       1.92                  PEGASUS_ASSERT(false);
609 karl        1.91      #endif
610 kumpf       1.92              }
611                               // open the socket
612                               _bind();
613                           }
614                           else
615                           {
616 marek       1.95              PEG_TRACE_CSTRING(TRC_DISCARDED_DATA, Tracer::LEVEL2,
617 kumpf       1.92                  "HTTPAcceptor::reconnectConnectionSocket failure _rep is null.");
618                           }
619 karl        1.91      }
620                       
621                       /**
622 kumpf       1.92          getOutstandingRequestCount - returns the number of outstanding requests.
623 karl        1.91      */
624                       Uint32 HTTPAcceptor::getOutstandingRequestCount() const
625                       {
626 kumpf       1.92          Uint32 count = 0;
627                           if (_rep)
628                           {
629                               AutoMutex autoMut(_rep->_connection_mut);
630                               if (_rep->connections.size() > 0)
631                               {
632                                   HTTPConnection* connection = _rep->connections[0];
633                                   count = connection->getRequestCount();
634                               }
635                           }
636                           return count;
637 karl        1.91      }
638                       
639                       
640                       /**
641                           getPortNumber - returns the port number used for the connection
642                       */
643                       Uint32 HTTPAcceptor::getPortNumber() const
644                       {
645                           return _portNumber;
646                       }
647                       
648                       void HTTPAcceptor::setSocketWriteTimeout(Uint32 socketWriteTimeout)
649                       {
650                           _socketWriteTimeout = socketWriteTimeout;
651                       }
652                       
653 dave.sudlik 1.106.2.1 void HTTPAcceptor::setIdleConnectionTimeout(Uint32 idleConnectionTimeoutSeconds)
654                       {
655                           _idleConnectionTimeoutSeconds = idleConnectionTimeoutSeconds;
656                       }
657                       
658 karl        1.91      void HTTPAcceptor::unbind()
659                       {
660 kumpf       1.92          if (_rep)
661                           {
662                               _portNumber = 0;
663                               Socket::close(_rep->socket);
664 karl        1.91      
665 dave.sudlik 1.101             if (_connectionType == LOCAL_CONNECTION)
666 kumpf       1.92              {
667 karl        1.91      #ifndef PEGASUS_DISABLE_LOCAL_DOMAIN_SOCKET
668 kumpf       1.92                  ::unlink(
669                                       reinterpret_cast<struct sockaddr_un*>(_rep->address)->sun_path);
670 karl        1.91      #else
671 kumpf       1.92                  PEGASUS_ASSERT(false);
672 karl        1.91      #endif
673 kumpf       1.92              }
674 karl        1.91      
675 kumpf       1.92              delete _rep;
676                               _rep = 0;
677                           }
678                           else
679                           {
680 marek       1.95              PEG_TRACE_CSTRING(TRC_DISCARDED_DATA, Tracer::LEVEL2,
681 kumpf       1.92                  "HTTPAcceptor::unbind failure _rep is null." );
682                           }
683 karl        1.91      }
684                       
685                       void HTTPAcceptor::destroyConnections()
686                       {
687 kumpf       1.92          if (_rep)
688                           {
689                               // For each connection created by this object:
690 karl        1.91      
691 kumpf       1.92              AutoMutex autoMut(_rep->_connection_mut);
692                               for (Uint32 i = 0, n = _rep->connections.size(); i < n; i++)
693                               {
694                                   HTTPConnection* connection = _rep->connections[i];
695                                   SocketHandle socket = connection->getSocket();
696 karl        1.91      
697 kumpf       1.92                  // Unsolicit SocketMessages:
698 karl        1.91      
699 kumpf       1.92                  _monitor->unsolicitSocketMessages(socket);
700 karl        1.91      
701 kumpf       1.92                  // Destroy the connection (causing it to close):
702 karl        1.91      
703 kumpf       1.92                  while (connection->refcount.get()) { }
704                                   delete connection;
705                               }
706 karl        1.91      
707 kumpf       1.92              _rep->connections.clear();
708                           }
709 karl        1.91      }
710                       
711                       void HTTPAcceptor::_acceptConnection()
712                       {
713 kumpf       1.92          // This function cannot be called on an invalid socket!
714 karl        1.91      
715 kumpf       1.92          PEGASUS_ASSERT(_rep != 0);
716 karl        1.91      
717 kumpf       1.92          // Accept the connection (populate the address):
718 karl        1.91      
719 kumpf       1.92          struct sockaddr* accept_address;
720                           SocketLength address_size;
721 karl        1.91      
722 dave.sudlik 1.101         if (_connectionType == LOCAL_CONNECTION)
723 kumpf       1.92          {
724 karl        1.91      #ifndef PEGASUS_DISABLE_LOCAL_DOMAIN_SOCKET
725 kumpf       1.92              accept_address =
726                                   reinterpret_cast<struct sockaddr*>(new struct sockaddr_un);
727                               address_size = sizeof(struct sockaddr_un);
728 karl        1.91      #else
729 kumpf       1.92              PEGASUS_ASSERT(false);
730 karl        1.91      #endif
731 kumpf       1.92          }
732                           else
733                           {
734 dave.sudlik 1.101     #ifdef PEGASUS_ENABLE_IPV6
735                               accept_address =
736                                  reinterpret_cast<struct sockaddr*>
737                                  (new struct sockaddr_storage);
738                               address_size = sizeof(struct sockaddr_storage);
739                       #else
740 kumpf       1.92              accept_address =
741                                   reinterpret_cast<struct sockaddr*>(new struct sockaddr_in);
742                               address_size = sizeof(struct sockaddr_in);
743 dave.sudlik 1.101     #endif
744 kumpf       1.92          }
745                       
746 kumpf       1.106.2.2     // It is not necessary to handle EINTR errors from this accept() call.
747                           // An EINTR error should not occur on a non-blocking socket.  If the
748                           // listen socket is blocking and EINTR occurs, the new socket connection
749                           // is not accepted here.
750                       
751                           // EAGAIN errors are also not handled here.  An EAGAIN error should not
752                           // occur after select() indicates that the listen socket is available for
753                           // reading.  If the accept() fails with an EAGAIN error code, a new
754                           // connection is not accepted here.
755                       
756                           SocketHandle socket = accept(_rep->socket, accept_address, &address_size);
757 kumpf       1.92      
758                           if (socket == PEGASUS_SOCKET_ERROR)
759                           {
760                               // the remote connection is invalid, destroy client address.
761                               delete accept_address;
762                       
763                               // TCPIP is down reconnect this acceptor
764                               if (getSocketError() == PEGASUS_NETWORK_TCPIP_STOPPED)
765                               {
766 marek       1.95                  PEG_TRACE_CSTRING(TRC_DISCARDED_DATA, Tracer::LEVEL2,
767 kumpf       1.92                      "Socket has an IO error. TCP/IP down. Try to reconnect.");
768                       
769                                   reconnectConnectionSocket();
770                       
771                                   return;
772                               }
773 karl        1.91      
774 kumpf       1.92              Logger::put(Logger::STANDARD_LOG, System::CIMSERVER, Logger::TRACE,
775                                   "HTTPAcceptor - accept() failure.  errno: $0", errno);
776 karl        1.91      
777 marek       1.95              PEG_TRACE_CSTRING(TRC_DISCARDED_DATA, Tracer::LEVEL2,
778 kumpf       1.92                  "HTTPAcceptor: accept() failed");
779                               return;
780                           }
781 karl        1.91      
782 kumpf       1.92          String ipAddress;
783 karl        1.91      
784 dave.sudlik 1.101         if (_connectionType == LOCAL_CONNECTION)
785 kumpf       1.92          {
786                               ipAddress = "localhost";
787                           }
788                           else
789                           {
790 dave.sudlik 1.101     #ifdef PEGASUS_ENABLE_IPV6
791                               char ipBuffer[PEGASUS_INET6_ADDRSTR_LEN];
792 dmitry.mikulin 1.105             int rc;
793 dmitry.mikulin 1.106             if ((rc = System::getNameInfo(accept_address, 
794                                          address_size, 
795                                          ipBuffer,
796                                          PEGASUS_INET6_ADDRSTR_LEN, 
797                                          0, 
798                                          0, 
799                                          NI_NUMERICHOST)))
800 dave.sudlik    1.101             {
801                                      Logger::put(Logger::STANDARD_LOG, System::CIMSERVER, Logger::TRACE,
802                                          "HTTPAcceptor - getnameinfo() failure.  rc: $0", rc);
803                          
804                                      PEG_TRACE_CSTRING(TRC_DISCARDED_DATA, Tracer::LEVEL2,
805                                          "HTTPAcceptor: getnameinfo() failed");
806                                      delete accept_address;
807                                      Socket::close(socket);
808                                      return;
809                                  }
810                                  ipAddress = ipBuffer;
811                          #else
812 kumpf          1.92              unsigned char* sa = reinterpret_cast<unsigned char*>(
813                                      &reinterpret_cast<struct sockaddr_in*>(
814                                          accept_address)->sin_addr.s_addr);
815                                  char ipBuffer[32];
816                                  sprintf(ipBuffer, "%u.%u.%u.%u", sa[0], sa[1], sa[2], sa[3]);
817                                  ipAddress = ipBuffer;
818 dave.sudlik    1.101     #endif
819 kumpf          1.92          }
820 karl           1.91      
821 kumpf          1.92          delete accept_address;
822 karl           1.91      
823                          // set the close on exec flag
824                          #if !defined(PEGASUS_OS_TYPE_WINDOWS) && !defined(PEGASUS_OS_VMS)
825 kumpf          1.92          int sock_flags;
826                              if ((sock_flags = fcntl(socket, F_GETFD, 0)) < 0)
827                              {
828 marek          1.95              PEG_TRACE_CSTRING(TRC_DISCARDED_DATA, Tracer::LEVEL2,
829 kumpf          1.92                  "HTTPAcceptor: fcntl(F_GETFD) failed");
830                              }
831                              else
832                              {
833                                  sock_flags |= FD_CLOEXEC;
834                                  if (fcntl(socket, F_SETFD, sock_flags) < 0)
835                                  {
836 marek          1.95                  PEG_TRACE_CSTRING(TRC_DISCARDED_DATA, Tracer::LEVEL2,
837 kumpf          1.92                      "HTTPAcceptor: fcntl(F_SETFD) failed");
838                                  }
839                              }
840 karl           1.91      #endif
841                          
842                          
843 kumpf          1.92          PEG_LOGGER_TRACE((Logger::STANDARD_LOG, System::CIMSERVER, 0,
844                                  "HTTPAcceptor - accept() success.  Socket: $1" ,socket));
845                          
846 kumpf          1.96          SharedPtr<MP_Socket> mp_socket(new MP_Socket(
847 sushma.fernandes 1.97              socket, _sslcontext, _sslContextObjectLock, ipAddress));
848 kumpf            1.92      
849 kumpf            1.106.2.2     mp_socket->disableBlocking();
850 kumpf            1.92          mp_socket->setSocketWriteTimeout(_socketWriteTimeout);
851                            
852 kumpf            1.106.2.2     // Perform the SSL handshake, if applicable.
853 kumpf            1.92      
854                                Sint32 socketAcceptStatus = mp_socket->accept();
855                            
856                                if (socketAcceptStatus < 0)
857                                {
858 marek            1.95              PEG_TRACE_CSTRING(TRC_DISCARDED_DATA, Tracer::LEVEL2,
859 kumpf            1.92                  "HTTPAcceptor: SSL_accept() failed");
860                                    mp_socket->close();
861                                    return;
862                                }
863                            
864                                // Create a new connection and add it to the connection list:
865                            
866                                HTTPConnection* connection = new HTTPConnection(_monitor, mp_socket,
867                                    ipAddress, this, static_cast<MessageQueue *>(_outputMessageQueue));
868                            
869 dave.sudlik      1.106.2.1     if (_idleConnectionTimeoutSeconds)
870                                {
871                                    connection->_idleConnectionTimeoutSeconds = 
872                                        _idleConnectionTimeoutSeconds;
873                                    Time::gettimeofday(&connection->_idleStartTime);
874                                }
875                            
876 kumpf            1.92          if (socketAcceptStatus == 0)
877                                {
878 marek            1.95              PEG_TRACE_CSTRING(TRC_HTTP, Tracer::LEVEL2,
879 kumpf            1.92                  "HTTPAcceptor: SSL_accept() pending");
880                                    connection->_acceptPending = true;
881 dave.sudlik      1.106.2.1         Time::gettimeofday(&connection->_acceptPendingStartTime);
882 kumpf            1.92          }
883 karl             1.91      
884 kumpf            1.92          // Solicit events on this new connection's socket:
885                                int index;
886 karl             1.91      
887 kumpf            1.92          if (-1 ==  (index = _monitor->solicitSocketMessages(
888                                        connection->getSocket(),
889                                        SocketMessage::READ | SocketMessage::EXCEPTION,
890                                        connection->getQueueId(), Monitor::CONNECTION)) )
891                                {
892                                    // ATTN-DE-P2-2003100503::TODO::Need to enhance code to return
893                                    // an error message to Client application.
894 marek            1.95              PEG_TRACE_CSTRING(TRC_DISCARDED_DATA, Tracer::LEVEL2,
895 kumpf            1.92                  "HTTPAcceptor::_acceptConnection: Attempt to allocate entry in "
896                                            "_entries table failed.");
897                                    delete connection;
898                                    Socket::close(socket);
899                                    return;
900                                }
901 karl             1.91      
902 kumpf            1.92          // Save the socket for cleanup later:
903                                connection->_entry_index = index;
904                                AutoMutex autoMut(_rep->_connection_mut);
905                                _rep->connections.append(connection);
906 karl             1.91      }
907                            
908 kumpf            1.92      PEGASUS_NAMESPACE_END

No CVS admin address has been configured
Powered by
ViewCVS 0.9.2