(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.5     // We need to ensure that the socket number is not higher than
758                          // what fits into FD_SETSIZE, because we else won't be able to select on it
759                          // and won't ever communicate correct on that socket.
760                          if (socket >= FD_SETSIZE)
761                          {
762                              // the remote connection is invalid, destroy client address.
763                              delete accept_address;
764                              
765                              Logger::put(Logger::STANDARD_LOG, System::CIMSERVER, Logger::TRACE,
766                                  "HTTPAcceptor out of available sockets. "
767                                      "Closing connection to the new client.");
768                      
769                              PEG_TRACE(
770                                  (TRC_DISCARDED_DATA,
771                                   Tracer::LEVEL2,
772                                   "accept() returned too large socket number %d.",
773                                   socket));
774                              
775                              // close the connection
776                              Socket::close(socket);
777                              return;
778 marek       1.93.4.5     }
779 sushma.fernandes 1.93.4.7 
780 karl             1.91     
781 kumpf            1.92         String ipAddress;
782 karl             1.91     
783 dave.sudlik      1.93.4.2     if (_connectionType == LOCAL_CONNECTION)
784 kumpf            1.92         {
785                                   ipAddress = "localhost";
786                               }
787                               else
788                               {
789 dave.sudlik      1.93.4.2 #ifdef PEGASUS_ENABLE_IPV6
790                                   char ipBuffer[PEGASUS_INET6_ADDRSTR_LEN];
791                                   int rc;
792                                   while ((rc = getnameinfo(accept_address, address_size, ipBuffer,
793                                       PEGASUS_INET6_ADDRSTR_LEN, 0, 0, NI_NUMERICHOST)) == EAI_AGAIN)
794                                       ;
795                                   if (rc)
796                                   {
797                                       Logger::put(Logger::STANDARD_LOG, System::CIMSERVER, Logger::TRACE,
798                                           "HTTPAcceptor - getnameinfo() failure.  rc: $0", rc);
799                           
800                                       PEG_TRACE_CSTRING(TRC_DISCARDED_DATA, Tracer::LEVEL2,
801                                           "HTTPAcceptor: getnameinfo() failed");
802                                       delete accept_address;
803                                       Socket::close(socket);
804                                       return;
805                                   }
806                                   ipAddress = ipBuffer;
807                           #else
808 kumpf            1.92             unsigned char* sa = reinterpret_cast<unsigned char*>(
809                                       &reinterpret_cast<struct sockaddr_in*>(
810                                           accept_address)->sin_addr.s_addr);
811                                   char ipBuffer[32];
812                                   sprintf(ipBuffer, "%u.%u.%u.%u", sa[0], sa[1], sa[2], sa[3]);
813                                   ipAddress = ipBuffer;
814 dave.sudlik      1.93.4.2 #endif
815 kumpf            1.92         }
816 karl             1.91     
817 kumpf            1.92         delete accept_address;
818 karl             1.91     
819                           // set the close on exec flag
820                           #if !defined(PEGASUS_OS_TYPE_WINDOWS) && !defined(PEGASUS_OS_VMS)
821 kumpf            1.92         int sock_flags;
822                               if ((sock_flags = fcntl(socket, F_GETFD, 0)) < 0)
823                               {
824 marek            1.93.4.1         PEG_TRACE_CSTRING(TRC_DISCARDED_DATA, Tracer::LEVEL2,
825 kumpf            1.92                 "HTTPAcceptor: fcntl(F_GETFD) failed");
826                               }
827                               else
828                               {
829                                   sock_flags |= FD_CLOEXEC;
830                                   if (fcntl(socket, F_SETFD, sock_flags) < 0)
831                                   {
832 marek            1.93.4.1             PEG_TRACE_CSTRING(TRC_DISCARDED_DATA, Tracer::LEVEL2,
833 kumpf            1.92                     "HTTPAcceptor: fcntl(F_SETFD) failed");
834                                   }
835                               }
836 karl             1.91     #endif
837                           
838                           
839 kumpf            1.92         PEG_LOGGER_TRACE((Logger::STANDARD_LOG, System::CIMSERVER, 0,
840                                   "HTTPAcceptor - accept() success.  Socket: $1" ,socket));
841                           
842                               AutoPtr<MP_Socket> mp_socket(new MP_Socket(
843                                   socket, _sslcontext, _sslContextObjectLock));
844                           
845 kumpf            1.93.4.4     mp_socket->disableBlocking();
846 kumpf            1.92         mp_socket->setSocketWriteTimeout(_socketWriteTimeout);
847                           
848 kumpf            1.93.4.4     // Perform the SSL handshake, if applicable.
849 kumpf            1.92     
850                               Sint32 socketAcceptStatus = mp_socket->accept();
851                           
852                               if (socketAcceptStatus < 0)
853                               {
854 marek            1.93.4.1         PEG_TRACE_CSTRING(TRC_DISCARDED_DATA, Tracer::LEVEL2,
855 kumpf            1.92                 "HTTPAcceptor: SSL_accept() failed");
856                                   mp_socket->close();
857                                   return;
858                               }
859                           
860                               // Create a new connection and add it to the connection list:
861                           
862                               HTTPConnection* connection = new HTTPConnection(_monitor, mp_socket,
863                                   ipAddress, this, static_cast<MessageQueue *>(_outputMessageQueue));
864                           
865 dave.sudlik      1.93.4.3     if (_idleConnectionTimeoutSeconds)
866                               {
867                                   connection->_idleConnectionTimeoutSeconds = 
868                                       _idleConnectionTimeoutSeconds;
869                                   Time::gettimeofday(&connection->_idleStartTime);
870                               }
871                           
872 kumpf            1.92         if (socketAcceptStatus == 0)
873                               {
874 marek            1.93.4.1         PEG_TRACE_CSTRING(TRC_HTTP, Tracer::LEVEL2,
875 kumpf            1.92                 "HTTPAcceptor: SSL_accept() pending");
876                                   connection->_acceptPending = true;
877 dave.sudlik      1.93.4.3         Time::gettimeofday(&connection->_acceptPendingStartTime); 
878 kumpf            1.92         }
879 karl             1.91     
880 kumpf            1.92         // Solicit events on this new connection's socket:
881                               int index;
882 karl             1.91     
883 kumpf            1.92         if (-1 ==  (index = _monitor->solicitSocketMessages(
884                                       connection->getSocket(),
885                                       SocketMessage::READ | SocketMessage::EXCEPTION,
886                                       connection->getQueueId(), Monitor::CONNECTION)) )
887                               {
888                                   // ATTN-DE-P2-2003100503::TODO::Need to enhance code to return
889                                   // an error message to Client application.
890 marek            1.93.4.1         PEG_TRACE_CSTRING(TRC_DISCARDED_DATA, Tracer::LEVEL2,
891 kumpf            1.92                 "HTTPAcceptor::_acceptConnection: Attempt to allocate entry in "
892                                           "_entries table failed.");
893                                   delete connection;
894                                   Socket::close(socket);
895                                   return;
896                               }
897 karl             1.91     
898 kumpf            1.92         // Save the socket for cleanup later:
899                               connection->_entry_index = index;
900                               AutoMutex autoMut(_rep->_connection_mut);
901                               _rep->connections.append(connection);
902 karl             1.91     }
903                           
904 kumpf            1.92     PEGASUS_NAMESPACE_END

No CVS admin address has been configured
Powered by
ViewCVS 0.9.2