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

No CVS admin address has been configured
Powered by
ViewCVS 0.9.2