(file) Return to HTTPAcceptor.cpp CVS log (file) (dir) Up to [Pegasus] / pegasus / src / Pegasus / Common

  1 mike  1.2 //%/////////////////////////////////////////////////////////////////////////////
  2           //
  3           // Copyright (c) 2000, 2001 BMC Software, Hewlett-Packard Company, IBM, 
  4           // The Open Group, Tivoli Systems
  5           //
  6           // Permission is hereby granted, free of charge, to any person obtaining a copy
  7           // of this software and associated documentation files (the "Software"), to 
  8           // deal in the Software without restriction, including without limitation the 
  9           // rights to use, copy, modify, merge, publish, distribute, sublicense, and/or 
 10           // sell copies of the Software, and to permit persons to whom the Software is
 11           // furnished to do so, subject to the following conditions:
 12           // 
 13           // THE ABOVE COPYRIGHT NOTICE AND THIS PERMISSION NOTICE SHALL BE INCLUDED IN 
 14           // ALL COPIES OR SUBSTANTIAL PORTIONS OF THE SOFTWARE. THE SOFTWARE IS PROVIDED
 15           // "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT
 16           // LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR 
 17           // PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT 
 18           // HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN 
 19           // ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
 20           // WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
 21           //
 22 mike  1.2 //==============================================================================
 23           //
 24           // Author: Mike Brasher (mbrasher@bmc.com)
 25           //
 26           // Modified By:
 27           //         Jenny Yu, Hewlett-Packard Company (jenny_yu@hp.com)
 28 kumpf 1.6 //         Nag Boranna, Hewlett-Packard Company (nagaraja_boranna@hp.com)
 29 mike  1.2 //
 30           //%/////////////////////////////////////////////////////////////////////////////
 31           
 32           #include "Config.h"
 33 kumpf 1.15 #include "Constants.h"
 34 mike  1.2  #include <iostream>
 35            #include "Socket.h"
 36            
 37            #ifdef PEGASUS_PLATFORM_WIN32_IX86_MSVC
 38 mday  1.12 #include <windows.h>
 39 mike  1.2  #else
 40            # include <cctype>
 41            # include <unistd.h>
 42            # include <cstdlib>
 43            # include <errno.h>
 44            # include <fcntl.h>
 45            # include <netdb.h>
 46            # include <netinet/in.h>
 47            # include <arpa/inet.h>
 48            # include <sys/socket.h>
 49 kumpf 1.11 # ifdef PEGASUS_LOCAL_DOMAIN_SOCKET
 50            #  include <sys/un.h>
 51            # endif
 52 mike  1.2  #endif
 53            
 54            #include "Socket.h"
 55            #include "TLS.h"
 56            #include "HTTPAcceptor.h"
 57            #include "HTTPConnection.h"
 58            
 59            PEGASUS_USING_STD;
 60            
 61            PEGASUS_NAMESPACE_BEGIN
 62            
 63            ////////////////////////////////////////////////////////////////////////////////
 64            //
 65            // HTTPAcceptorRep
 66            //
 67            ////////////////////////////////////////////////////////////////////////////////
 68            
 69            struct HTTPAcceptorRep
 70            {
 71 kumpf 1.11 #ifdef PEGASUS_LOCAL_DOMAIN_SOCKET
 72                  struct sockaddr_un address;
 73            #else
 74 mday  1.7        struct sockaddr_in address;
 75 kumpf 1.11 #endif
 76 mday  1.7        Sint32 socket;
 77                  Array<HTTPConnection*> connections;
 78 mike  1.2  };
 79            
 80            ////////////////////////////////////////////////////////////////////////////////
 81            //
 82            // HTTPAcceptor
 83            //
 84            ////////////////////////////////////////////////////////////////////////////////
 85            
 86 mday  1.9  HTTPAcceptor::HTTPAcceptor(Monitor* monitor, MessageQueueService* outputMessageQueue)
 87 kumpf 1.15    : Base(PEGASUS_QUEUENAME_HTTPACCEPTOR), 
 88 mday  1.7       _monitor(monitor), _outputMessageQueue(outputMessageQueue), 
 89                 _rep(0), _sslcontext(NULL)
 90 mike  1.2  {
 91 mday  1.5  
 92 mday  1.7     Socket::initializeInterface();
 93 mike  1.2  }
 94            
 95 mday  1.9  HTTPAcceptor::HTTPAcceptor(Monitor* monitor, MessageQueueService* outputMessageQueue,
 96 mike  1.2                             SSLContext * sslcontext)
 97 kumpf 1.15    :       Base(PEGASUS_QUEUENAME_HTTPACCEPTOR), 
 98 mday  1.16 	   _monitor(monitor), _outputMessageQueue(outputMessageQueue), 
 99            	   _rep(0),
100 mday  1.5  	   _sslcontext(sslcontext)
101 mike  1.2  {
102 mday  1.7     Socket::initializeInterface();
103 mike  1.2  }
104            
105            HTTPAcceptor::~HTTPAcceptor()
106            {
107 mday  1.7     unbind();
108               Socket::uninitializeInterface();
109 mike  1.2  }
110            
111 mday  1.7  void HTTPAcceptor::handleEnqueue(Message *message)
112 mike  1.2  {
113 mday  1.7     if (! message)
114                  return;
115               
116               switch (message->getType())
117               {
118                  case SOCKET_MESSAGE:
119                  {
120            	 SocketMessage* socketMessage = (SocketMessage*)message;
121 mday  1.16 	 
122 mday  1.7  	 // If this is a connection request:
123            
124            	 if (socketMessage->socket == _rep->socket &&
125            	     socketMessage->events | SocketMessage::READ)
126            	 {
127            	    _acceptConnection();
128            	 }
129            	 else
130            	 {
131            	    // ATTN! this can't happen!
132            	 }
133            
134            	 break;
135                  }
136            
137                  case CLOSE_CONNECTION_MESSAGE:
138                  {
139            	 CloseConnectionMessage* closeConnectionMessage 
140            	    = (CloseConnectionMessage*)message;
141            
142            	 for (Uint32 i = 0, n = _rep->connections.size(); i < n; i++)
143 mday  1.7  	 {
144            	    HTTPConnection* connection = _rep->connections[i];	
145            	    Sint32 socket = connection->getSocket();
146 mike  1.2  
147 mday  1.7  	    if (socket == closeConnectionMessage->socket)
148 mike  1.2  	    {
149 mday  1.7  	       _monitor->unsolicitSocketMessages(socket);
150            	       _rep->connections.remove(i);
151 kumpf 1.17                while (connection->refcount.value()) { }
152                           delete connection;
153 mday  1.7  	       break;
154 mike  1.2  	    }
155 mday  1.7  	 }
156                  }
157 mike  1.2  
158 kumpf 1.10       default:
159                  // ATTN: need unexpected message error!
160 mday  1.7        break;
161               };
162 mike  1.2  
163 mday  1.7     delete message;
164            }
165 mike  1.2  
166            
167 mday  1.7  void HTTPAcceptor::handleEnqueue()
168            {
169               Message* message = dequeue();
170 mike  1.2  
171 mday  1.7     if (!message)
172                  return;
173               
174               handleEnqueue(message);
175 mike  1.2  
176            }
177            
178            void HTTPAcceptor::bind(Uint32 portNumber)
179            {
180 mday  1.7     if (_rep)
181                  throw BindFailed("HTTPAcceptor already bound");
182 mike  1.2  
183 mday  1.7     _rep = new HTTPAcceptorRep;
184 mike  1.2  
185 mday  1.7     _portNumber = portNumber;
186 mike  1.2  
187 mday  1.7     // bind address
188               _bind();
189 mike  1.2  
190 mday  1.7     return;
191 mike  1.2  }
192            
193            /**
194 mday  1.7     _bind - creates a new server socket and bind socket to the port address.
195 kumpf 1.11    If PEGASUS_LOCAL_DOMAIN_SOCKET is defined, the port number is ignored and
196               a domain socket is bound.
197 mike  1.2  */
198            void HTTPAcceptor::_bind()
199            {
200            
201 mday  1.7     // Create address:
202 mike  1.2  
203 mday  1.7     memset(&_rep->address, 0, sizeof(_rep->address));
204 kumpf 1.6  
205 kumpf 1.11 #ifdef PEGASUS_LOCAL_DOMAIN_SOCKET
206               _rep->address.sun_family = AF_UNIX;
207               strcpy(_rep->address.sun_path, "/var/opt/wbem/cimxml.socket");
208               ::unlink(_rep->address.sun_path);
209 kumpf 1.6  #else
210 mday  1.7     _rep->address.sin_addr.s_addr = INADDR_ANY;
211               _rep->address.sin_family = AF_INET;
212               _rep->address.sin_port = htons(_portNumber);
213 kumpf 1.11 #endif
214 mike  1.2  
215 mday  1.7     // Create socket:
216 mike  1.2      
217 kumpf 1.11 #ifdef PEGASUS_LOCAL_DOMAIN_SOCKET
218               _rep->socket = socket(AF_UNIX, SOCK_STREAM, 0);
219            #else
220 mday  1.7     _rep->socket = socket(PF_INET, SOCK_STREAM, IPPROTO_TCP);
221 kumpf 1.11 #endif
222 mike  1.2  
223 mday  1.7     if (_rep->socket < 0)
224               {
225                  delete _rep;
226                  _rep = 0;
227                  throw BindFailed("Failed to create socket");
228               }
229            
230               //
231               // Set the socket option SO_REUSEADDR to reuse the socket address so
232               // that we can rebind to a new socket using the same address when we
233               // need to resume the cimom as a result of a timeout during a Shutdown
234               // operation.
235               //
236               int opt=1;
237               if (setsockopt(_rep->socket, SOL_SOCKET, SO_REUSEADDR,
238            		  (char *)&opt, sizeof(opt)) < 0)
239               {
240                  delete _rep;
241                  _rep = 0;
242                  throw BindFailed("Failed to set socket option");
243               }
244 mday  1.7  
245               // Bind socket to port:
246            
247               if (::bind(_rep->socket, 
248 kumpf 1.10 	      reinterpret_cast<struct sockaddr*>(&_rep->address), 
249 mday  1.7  	      sizeof(_rep->address)) < 0)
250               {
251                  Socket::close(_rep->socket);
252                  delete _rep;
253                  _rep = 0;
254 kumpf 1.11       throw BindFailed("Failed to bind socket");
255 mday  1.7     }
256            
257 kumpf 1.11    // Set up listening on the given socket:
258 mday  1.7  
259               int const MAX_CONNECTION_QUEUE_LENGTH = 5;
260            
261               if (listen(_rep->socket, MAX_CONNECTION_QUEUE_LENGTH) < 0)
262               {
263                  Socket::close(_rep->socket);
264                  delete _rep;
265                  _rep = 0;
266 kumpf 1.11       throw BindFailed("Failed to bind socket");
267 mday  1.7     }
268            
269               // Register to receive SocketMessages on this socket:
270            
271               if (!_monitor->solicitSocketMessages(
272            	  _rep->socket,
273            	  SocketMessage::READ | SocketMessage::EXCEPTION,
274 mday  1.16 	  getQueueId(), 
275            	  Monitor::ACCEPTOR))
276 mday  1.7     {
277                  Socket::close(_rep->socket);
278                  delete _rep;
279                  _rep = 0;
280                  throw BindFailed("Failed to solicit socket messaeges");
281               }
282 mike  1.2  }
283            
284            /**
285 mday  1.7     closeConnectionSocket - close the server listening socket to disallow
286               new client connections.
287 mike  1.2  */
288            void HTTPAcceptor::closeConnectionSocket()
289            {
290 mday  1.7     if (_rep)
291               {
292                  // unregister the socket
293                  _monitor->unsolicitSocketMessages(_rep->socket);
294            
295                  // close the socket
296                  Socket::close(_rep->socket);
297               }
298 mike  1.2  }
299            
300            /**
301 mday  1.7     reopenConnectionSocket - creates a new server socket.
302 mike  1.2  */
303            void HTTPAcceptor::reopenConnectionSocket()
304            {
305 mday  1.7     if (_rep)
306               {
307                  _bind();
308               }
309 mike  1.2  }
310            
311            /**
312 mday  1.7     getOutstandingRequestCount - returns the number of outstanding requests.
313 mike  1.2  */
314            Uint32 HTTPAcceptor::getOutstandingRequestCount()
315            {
316 mday  1.7     if (_rep->connections.size() > 0)
317               {
318                  HTTPConnection* connection = _rep->connections[0];	
319                  return(connection->getRequestCount());
320               }
321               else
322               {
323                  return(0);
324               }
325 mike  1.2  }
326            
327            void HTTPAcceptor::unbind()
328            {
329 mday  1.7     if (_rep)
330               {
331                  Socket::close(_rep->socket);
332                  delete _rep;
333                  _rep = 0;
334               }
335 mike  1.2  }
336            
337            void HTTPAcceptor::destroyConnections()
338            {
339 mday  1.7     // For each connection created by this object:
340 mike  1.2  
341 mday  1.7     for (Uint32 i = 0, n = _rep->connections.size(); i < n; i++)
342               {
343                  HTTPConnection* connection = _rep->connections[i];	
344                  Sint32 socket = connection->getSocket();
345 mike  1.2  
346 mday  1.7        // Unsolicit SocketMessages:
347 mike  1.2  
348 mday  1.7        _monitor->unsolicitSocketMessages(socket);
349 mike  1.2  
350 mday  1.7        // Destroy the connection (causing it to close):
351 mike  1.2  
352 kumpf 1.17       while (connection->refcount.value()) { }
353 mday  1.7        delete connection;
354               }
355 mike  1.2  
356 mday  1.7     _rep->connections.clear();
357 mike  1.2  }
358            
359            void HTTPAcceptor::_acceptConnection()
360            {
361 mday  1.7     // This function cannot be called on an invalid socket!
362 mike  1.2  
363 mday  1.7     PEGASUS_ASSERT(_rep != 0);
364 mike  1.2  
365 mday  1.7     if (!_rep)
366                  return;
367 mike  1.2  
368 mday  1.7     // Accept the connection (populate the address):
369 mike  1.2  
370 mday  1.7     sockaddr_in address;
371 mike  1.2  
372 sage  1.4  #if defined(PEGASUS_PLATFORM_ZOS_ZSERIES_IBM) || defined(PEGASUS_PLATFORM_AIX_RS_IBMCXX)
373 mday  1.7     size_t n = sizeof(address);
374 mike  1.2  #else
375 mday  1.7     int n = sizeof(address);
376 mike  1.2  #endif
377            
378 kumpf 1.14 #if defined(PEGASUS_PLATFORM_LINUX_IX86_GNU) || defined(PEGASUS_PLATFORM_LINUX_GENERIC_GNU)
379 mday  1.7     Sint32 socket = accept(
380                  _rep->socket, (struct sockaddr*)&address, (socklen_t *)&n);
381 mike  1.2  #else
382 kumpf 1.10    Sint32 socket = accept(_rep->socket, reinterpret_cast<struct sockaddr*>(&address), &n);
383 mike  1.2  #endif
384            
385 mday  1.7     if (socket < 0)
386               {
387                  if (getenv("PEGASUS_TRACE"))
388            	 cerr <<"HTTPAcceptor: accept() failed" << endl;
389 mike  1.2  
390 mday  1.7        return;
391               }
392 mike  1.2  
393 mday  1.7     // Create a new conection and add it to the connection list:
394 mike  1.2  
395 mday  1.7     MP_Socket * mp_socket = new MP_Socket(socket, _sslcontext);
396               if (mp_socket->accept() < 0) {
397                  if (getenv("PEGASUS_TRACE"))
398            	 cerr <<"HTTPAcceptor: SSL_accept() failed" << endl;
399 mike  1.2  
400 mday  1.7        return;
401               }
402 mike  1.2  
403 mday  1.7     HTTPConnection* connection = new HTTPConnection(
404 mday  1.16       _monitor, mp_socket, this, static_cast<MessageQueue *>(_outputMessageQueue));
405 mike  1.2  
406 mday  1.7     // Solicit events on this new connection's socket:
407 mike  1.2  
408 mday  1.7     if (!_monitor->solicitSocketMessages(
409            	  socket,
410            	  SocketMessage::READ | SocketMessage::EXCEPTION,
411 mday  1.16 	  connection->getQueueId(), Monitor::CONNECTION))
412 mday  1.7     {
413                  delete connection;
414                  Socket::close(socket);
415               }
416 mike  1.2  
417 mday  1.7     // Save the socket for cleanup later:
418 mike  1.2  
419 mday  1.7     _rep->connections.append(connection);
420 mike  1.2  }
421            
422            PEGASUS_NAMESPACE_END

No CVS admin address has been configured
Powered by
ViewCVS 0.9.2