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

No CVS admin address has been configured
Powered by
ViewCVS 0.9.2