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

No CVS admin address has been configured
Powered by
ViewCVS 0.9.2