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

  1 mike  1.2 //%/////////////////////////////////////////////////////////////////////////////
  2           //
  3 kumpf 1.20 // Copyright (c) 2000, 2001, 2002 BMC Software, Hewlett-Packard Company, IBM,
  4 mike  1.2  // The Open Group, Tivoli Systems
  5            //
  6            // Permission is hereby granted, free of charge, to any person obtaining a copy
  7 kumpf 1.20 // 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 mike  1.2  // 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 kumpf 1.20 // THE ABOVE COPYRIGHT NOTICE AND THIS PERMISSION NOTICE SHALL BE INCLUDED IN
 14 mike  1.2  // 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 kumpf 1.20 // 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 mike  1.2  // 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            //==============================================================================
 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 kumpf 1.19 #include "Tracer.h"
 59 mike  1.2  
 60            PEGASUS_USING_STD;
 61            
 62            PEGASUS_NAMESPACE_BEGIN
 63            
 64            ////////////////////////////////////////////////////////////////////////////////
 65            //
 66            // HTTPAcceptorRep
 67            //
 68            ////////////////////////////////////////////////////////////////////////////////
 69            
 70            struct HTTPAcceptorRep
 71            {
 72 kumpf 1.11 #ifdef PEGASUS_LOCAL_DOMAIN_SOCKET
 73                  struct sockaddr_un address;
 74            #else
 75 mday  1.7        struct sockaddr_in address;
 76 kumpf 1.11 #endif
 77 mday  1.7        Sint32 socket;
 78                  Array<HTTPConnection*> connections;
 79 mike  1.2  };
 80            
 81            ////////////////////////////////////////////////////////////////////////////////
 82            //
 83            // HTTPAcceptor
 84            //
 85            ////////////////////////////////////////////////////////////////////////////////
 86            
 87 kumpf 1.18 HTTPAcceptor::HTTPAcceptor(Monitor* monitor, MessageQueue* outputMessageQueue)
 88 kumpf 1.15    : Base(PEGASUS_QUEUENAME_HTTPACCEPTOR), 
 89 mday  1.7       _monitor(monitor), _outputMessageQueue(outputMessageQueue), 
 90 mday  1.21      _rep(0), _sslcontext(NULL), _entry_index(-1)
 91 mike  1.2  {
 92 mday  1.5  
 93 mday  1.7     Socket::initializeInterface();
 94 mike  1.2  }
 95            
 96 kumpf 1.18 HTTPAcceptor::HTTPAcceptor(Monitor* monitor, MessageQueue* outputMessageQueue,
 97 mike  1.2                             SSLContext * sslcontext)
 98 kumpf 1.15    :       Base(PEGASUS_QUEUENAME_HTTPACCEPTOR), 
 99 mday  1.16 	   _monitor(monitor), _outputMessageQueue(outputMessageQueue), 
100            	   _rep(0),
101 mday  1.21 	   _sslcontext(sslcontext),
102            	   _entry_index(-1)
103 mike  1.2  {
104 mday  1.7     Socket::initializeInterface();
105 mike  1.2  }
106            
107            HTTPAcceptor::~HTTPAcceptor()
108            {
109 mday  1.7     unbind();
110               Socket::uninitializeInterface();
111 mike  1.2  }
112            
113 mday  1.7  void HTTPAcceptor::handleEnqueue(Message *message)
114 mike  1.2  {
115 mday  1.7     if (! message)
116                  return;
117               
118               switch (message->getType())
119               {
120                  case SOCKET_MESSAGE:
121                  {
122            	 SocketMessage* socketMessage = (SocketMessage*)message;
123 mday  1.16 	 
124 mday  1.7  	 // If this is a connection request:
125            
126            	 if (socketMessage->socket == _rep->socket &&
127            	     socketMessage->events | SocketMessage::READ)
128            	 {
129            	    _acceptConnection();
130            	 }
131            	 else
132            	 {
133            	    // ATTN! this can't happen!
134            	 }
135            
136            	 break;
137                  }
138            
139                  case CLOSE_CONNECTION_MESSAGE:
140                  {
141            	 CloseConnectionMessage* closeConnectionMessage 
142            	    = (CloseConnectionMessage*)message;
143            
144            	 for (Uint32 i = 0, n = _rep->connections.size(); i < n; i++)
145 mday  1.7  	 {
146            	    HTTPConnection* connection = _rep->connections[i];	
147            	    Sint32 socket = connection->getSocket();
148 mike  1.2  
149 mday  1.7  	    if (socket == closeConnectionMessage->socket)
150 mike  1.2  	    {
151 mday  1.7  	       _monitor->unsolicitSocketMessages(socket);
152            	       _rep->connections.remove(i);
153 kumpf 1.17                delete connection;
154 mday  1.7  	       break;
155 mike  1.2  	    }
156 mday  1.7  	 }
157                  }
158 mike  1.2  
159 kumpf 1.10       default:
160                  // ATTN: need unexpected message error!
161 mday  1.7        break;
162               };
163 mike  1.2  
164 mday  1.7     delete message;
165            }
166 mike  1.2  
167            
168 mday  1.7  void HTTPAcceptor::handleEnqueue()
169            {
170               Message* message = dequeue();
171 mike  1.2  
172 mday  1.7     if (!message)
173                  return;
174               
175               handleEnqueue(message);
176 mike  1.2  
177            }
178            
179            void HTTPAcceptor::bind(Uint32 portNumber)
180            {
181 mday  1.7     if (_rep)
182 kumpf 1.23       throw BindFailedException("HTTPAcceptor already bound");
183 mike  1.2  
184 mday  1.7     _rep = new HTTPAcceptorRep;
185 mike  1.2  
186 mday  1.7     _portNumber = portNumber;
187 mike  1.2  
188 mday  1.7     // bind address
189               _bind();
190 mike  1.2  
191 mday  1.7     return;
192 mike  1.2  }
193            
194            /**
195 mday  1.7     _bind - creates a new server socket and bind socket to the port address.
196 kumpf 1.11    If PEGASUS_LOCAL_DOMAIN_SOCKET is defined, the port number is ignored and
197               a domain socket is bound.
198 mike  1.2  */
199            void HTTPAcceptor::_bind()
200            {
201            
202 mday  1.7     // Create address:
203 mike  1.2  
204 mday  1.7     memset(&_rep->address, 0, sizeof(_rep->address));
205 kumpf 1.6  
206 kumpf 1.11 #ifdef PEGASUS_LOCAL_DOMAIN_SOCKET
207               _rep->address.sun_family = AF_UNIX;
208               strcpy(_rep->address.sun_path, "/var/opt/wbem/cimxml.socket");
209               ::unlink(_rep->address.sun_path);
210 kumpf 1.6  #else
211 mday  1.7     _rep->address.sin_addr.s_addr = INADDR_ANY;
212               _rep->address.sin_family = AF_INET;
213               _rep->address.sin_port = htons(_portNumber);
214 kumpf 1.11 #endif
215 mike  1.2  
216 mday  1.7     // Create socket:
217 mike  1.2      
218 kumpf 1.11 #ifdef PEGASUS_LOCAL_DOMAIN_SOCKET
219               _rep->socket = socket(AF_UNIX, SOCK_STREAM, 0);
220            #else
221 mday  1.7     _rep->socket = socket(PF_INET, SOCK_STREAM, IPPROTO_TCP);
222 kumpf 1.11 #endif
223 mike  1.2  
224 mday  1.7     if (_rep->socket < 0)
225               {
226                  delete _rep;
227                  _rep = 0;
228 kumpf 1.23       throw BindFailedException("Failed to create socket");
229 mday  1.7     }
230            
231               //
232               // Set the socket option SO_REUSEADDR to reuse the socket address so
233               // that we can rebind to a new socket using the same address when we
234               // need to resume the cimom as a result of a timeout during a Shutdown
235               // operation.
236               //
237               int opt=1;
238               if (setsockopt(_rep->socket, SOL_SOCKET, SO_REUSEADDR,
239            		  (char *)&opt, sizeof(opt)) < 0)
240               {
241                  delete _rep;
242                  _rep = 0;
243 kumpf 1.23       throw BindFailedException("Failed to set socket option");
244 mday  1.7     }
245            
246               // Bind socket to port:
247            
248               if (::bind(_rep->socket, 
249 kumpf 1.10 	      reinterpret_cast<struct sockaddr*>(&_rep->address), 
250 mday  1.7  	      sizeof(_rep->address)) < 0)
251               {
252                  Socket::close(_rep->socket);
253                  delete _rep;
254                  _rep = 0;
255 kumpf 1.23       throw BindFailedException("Failed to bind socket");
256 mday  1.7     }
257            
258 kumpf 1.11    // Set up listening on the given socket:
259 mday  1.7  
260               int const MAX_CONNECTION_QUEUE_LENGTH = 5;
261            
262               if (listen(_rep->socket, MAX_CONNECTION_QUEUE_LENGTH) < 0)
263               {
264                  Socket::close(_rep->socket);
265                  delete _rep;
266                  _rep = 0;
267 kumpf 1.23       throw BindFailedException("Failed to bind socket");
268 mday  1.7     }
269            
270               // Register to receive SocketMessages on this socket:
271            
272 mday  1.21    if ( -1 == ( _entry_index = _monitor->solicitSocketMessages(
273 mday  1.7  	  _rep->socket,
274            	  SocketMessage::READ | SocketMessage::EXCEPTION,
275 mday  1.16 	  getQueueId(), 
276 mday  1.21 	  Monitor::ACCEPTOR)))
277 mday  1.7     {
278                  Socket::close(_rep->socket);
279                  delete _rep;
280                  _rep = 0;
281 kumpf 1.23       throw BindFailedException("Failed to solicit socket messaeges");
282 mday  1.7     }
283 mike  1.2  }
284            
285            /**
286 mday  1.7     closeConnectionSocket - close the server listening socket to disallow
287               new client connections.
288 mike  1.2  */
289            void HTTPAcceptor::closeConnectionSocket()
290            {
291 mday  1.7     if (_rep)
292               {
293                  // unregister the socket
294                  _monitor->unsolicitSocketMessages(_rep->socket);
295            
296                  // close the socket
297                  Socket::close(_rep->socket);
298               }
299 mike  1.2  }
300            
301            /**
302 mday  1.7     reopenConnectionSocket - creates a new server socket.
303 mike  1.2  */
304            void HTTPAcceptor::reopenConnectionSocket()
305            {
306 mday  1.7     if (_rep)
307               {
308                  _bind();
309               }
310 mike  1.2  }
311            
312            /**
313 mday  1.7     getOutstandingRequestCount - returns the number of outstanding requests.
314 mike  1.2  */
315            Uint32 HTTPAcceptor::getOutstandingRequestCount()
316            {
317 mday  1.7     if (_rep->connections.size() > 0)
318               {
319                  HTTPConnection* connection = _rep->connections[0];	
320                  return(connection->getRequestCount());
321               }
322               else
323               {
324                  return(0);
325               }
326 mike  1.2  }
327            
328            void HTTPAcceptor::unbind()
329            {
330 mday  1.7     if (_rep)
331               {
332                  Socket::close(_rep->socket);
333                  delete _rep;
334                  _rep = 0;
335               }
336 mike  1.2  }
337            
338            void HTTPAcceptor::destroyConnections()
339            {
340 mday  1.7     // For each connection created by this object:
341 mike  1.2  
342 mday  1.7     for (Uint32 i = 0, n = _rep->connections.size(); i < n; i++)
343               {
344                  HTTPConnection* connection = _rep->connections[i];	
345                  Sint32 socket = connection->getSocket();
346 mike  1.2  
347 mday  1.7        // Unsolicit SocketMessages:
348 mike  1.2  
349 mday  1.7        _monitor->unsolicitSocketMessages(socket);
350 mike  1.2  
351 mday  1.7        // Destroy the connection (causing it to close):
352 mike  1.2  
353 kumpf 1.17       while (connection->refcount.value()) { }
354 mday  1.7        delete connection;
355               }
356 mike  1.2  
357 mday  1.7     _rep->connections.clear();
358 mike  1.2  }
359            
360            void HTTPAcceptor::_acceptConnection()
361            {
362 mday  1.7     // This function cannot be called on an invalid socket!
363 mike  1.2  
364 mday  1.7     PEGASUS_ASSERT(_rep != 0);
365 mike  1.2  
366 mday  1.7     if (!_rep)
367                  return;
368 mike  1.2  
369 mday  1.7     // Accept the connection (populate the address):
370 mike  1.2  
371 mday  1.7     sockaddr_in address;
372 mike  1.2  
373 sage  1.4  #if defined(PEGASUS_PLATFORM_ZOS_ZSERIES_IBM) || defined(PEGASUS_PLATFORM_AIX_RS_IBMCXX)
374 mday  1.7     size_t n = sizeof(address);
375 mike  1.2  #else
376 mday  1.7     int n = sizeof(address);
377 mike  1.2  #endif
378            
379 kumpf 1.14 #if defined(PEGASUS_PLATFORM_LINUX_IX86_GNU) || defined(PEGASUS_PLATFORM_LINUX_GENERIC_GNU)
380 mday  1.7     Sint32 socket = accept(
381                  _rep->socket, (struct sockaddr*)&address, (socklen_t *)&n);
382 mike  1.2  #else
383 kumpf 1.10    Sint32 socket = accept(_rep->socket, reinterpret_cast<struct sockaddr*>(&address), &n);
384 mike  1.2  #endif
385            
386 mday  1.7     if (socket < 0)
387               {
388 kumpf 1.19        PEG_TRACE_STRING(TRC_HTTP, Tracer::LEVEL2,
389                                    "HTTPAcceptor: accept() failed");
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 kumpf 1.19    if (mp_socket->accept() < 0) 
397               {
398                   PEG_TRACE_STRING(TRC_HTTP, Tracer::LEVEL2,
399                                    "HTTPAcceptor: SSL_accept() failed");
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 mday  1.21    int index;
408               
409 mday  1.22    if (-1 ==  (index = _monitor->solicitSocketMessages(
410 mday  1.7  	  socket,
411            	  SocketMessage::READ | SocketMessage::EXCEPTION,
412 mday  1.21 	  connection->getQueueId(), Monitor::CONNECTION)) )
413 mday  1.7     {
414                  delete connection;
415                  Socket::close(socket);
416               }
417 mike  1.2  
418 mday  1.7     // Save the socket for cleanup later:
419 mday  1.21    connection->_entry_index = index;
420               
421 mday  1.7     _rep->connections.append(connection);
422 mike  1.2  }
423            
424            PEGASUS_NAMESPACE_END

No CVS admin address has been configured
Powered by
ViewCVS 0.9.2