(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           #include <iostream>
 34           #include "Socket.h"
 35           
 36           #ifdef PEGASUS_PLATFORM_WIN32_IX86_MSVC
 37           # include <winsock.h>
 38           #else
 39           # include <cctype>
 40           # include <unistd.h>
 41           # include <cstdlib>
 42           # include <errno.h>
 43           # include <fcntl.h>
 44           # include <netdb.h>
 45           # include <netinet/in.h>
 46           # include <arpa/inet.h>
 47           # include <sys/socket.h>
 48           #endif
 49           
 50 mike  1.2 #include "Socket.h"
 51           #include "TLS.h"
 52           #include "HTTPAcceptor.h"
 53           #include "HTTPConnection.h"
 54           
 55           PEGASUS_USING_STD;
 56           
 57           PEGASUS_NAMESPACE_BEGIN
 58           
 59           ////////////////////////////////////////////////////////////////////////////////
 60           //
 61           // HTTPAcceptorRep
 62           //
 63           ////////////////////////////////////////////////////////////////////////////////
 64           
 65           struct HTTPAcceptorRep
 66           {
 67               struct sockaddr_in address;
 68               Sint32 socket;
 69               Array<HTTPConnection*> connections;
 70           };
 71 mike  1.2 
 72           ////////////////////////////////////////////////////////////////////////////////
 73           //
 74           // HTTPAcceptor
 75           //
 76           ////////////////////////////////////////////////////////////////////////////////
 77           
 78           HTTPAcceptor::HTTPAcceptor(Monitor* monitor, MessageQueue* outputMessageQueue)
 79 mday  1.5     : Base("HTTPAcceptor", MessageQueue::getNextQueueId()), 
 80                 _monitor(monitor), _outputMessageQueue(outputMessageQueue), 
 81 mday  1.3       _rep(0), _sslcontext(NULL)
 82 mike  1.2 {
 83 mday  1.5 
 84 mike  1.2     Socket::initializeInterface();
 85           }
 86           
 87           HTTPAcceptor::HTTPAcceptor(Monitor* monitor, MessageQueue* outputMessageQueue,
 88                                      SSLContext * sslcontext)
 89 mday  1.5    :       Base("HTTPAcceptor", MessageQueue::getNextQueueId()), 
 90           	   _monitor(monitor), _outputMessageQueue(outputMessageQueue), _rep(0),
 91           	   _sslcontext(sslcontext)
 92 mike  1.2 {
 93               Socket::initializeInterface();
 94           }
 95           
 96           HTTPAcceptor::~HTTPAcceptor()
 97           {
 98               unbind();
 99               Socket::uninitializeInterface();
100           }
101           
102           void HTTPAcceptor::handleEnqueue()
103           {
104               Message* message = dequeue();
105           
106               if (!message)
107                   return;
108           
109               switch (message->getType())
110               {
111           	case SOCKET_MESSAGE:
112           	{
113 mike  1.2 	    SocketMessage* socketMessage = (SocketMessage*)message;
114           
115           	    // If this is a connection request:
116           
117           	    if (socketMessage->socket == _rep->socket &&
118           		socketMessage->events | SocketMessage::READ)
119           	    {
120           		_acceptConnection();
121           	    }
122           	    else
123           	    {
124           		// ATTN! this can't happen!
125           	    }
126           
127           	    break;
128           	}
129           
130           	case CLOSE_CONNECTION_MESSAGE:
131           	{
132           	    CloseConnectionMessage* closeConnectionMessage 
133           		= (CloseConnectionMessage*)message;
134 mike  1.2 
135           	    for (Uint32 i = 0, n = _rep->connections.size(); i < n; i++)
136           	    {
137           		HTTPConnection* connection = _rep->connections[i];	
138           		Sint32 socket = connection->getSocket();
139           
140           		if (socket == closeConnectionMessage->socket)
141           		{
142           		    _monitor->unsolicitSocketMessages(socket);
143           		    _rep->connections.remove(i);
144           		    delete connection;
145           		    break;
146           		}
147           	    }
148           	}
149           
150           	default:
151           	    // ATTN: need unexpected message error!
152           	    break;
153               };
154           
155 mike  1.2     delete message;
156           }
157           
158           const char* HTTPAcceptor::getQueueName() const
159           {
160               return "HTTPAcceptor";
161           }
162           
163           void HTTPAcceptor::bind(Uint32 portNumber)
164           {
165               if (_rep)
166           	throw BindFailed("HTTPAcceptor already bound");
167           
168               _rep = new HTTPAcceptorRep;
169           
170               _portNumber = portNumber;
171           
172               // bind address
173               _bind();
174           
175               return;
176 mike  1.2 }
177           
178           /**
179            _bind - creates a new server socket and bind socket to the port address.
180           */
181           void HTTPAcceptor::_bind()
182           {
183           
184               // Create address:
185           
186               memset(&_rep->address, 0, sizeof(_rep->address));
187 kumpf 1.6 
188           #ifdef PEGASUS_ACCEPT_ONLY_LOCAL_CONNECTIONS
189               _rep->address.sin_addr.s_addr = INADDR_LOOPBACK;
190           #else
191 mike  1.2     _rep->address.sin_addr.s_addr = INADDR_ANY;
192 kumpf 1.6 #endif
193           
194 mike  1.2     _rep->address.sin_family = AF_INET;
195               _rep->address.sin_port = htons(_portNumber);
196           
197               // Create socket:
198               
199               _rep->socket = socket(PF_INET, SOCK_STREAM, IPPROTO_TCP);
200           
201               if (_rep->socket < 0)
202               {
203           	delete _rep;
204           	_rep = 0;
205           	throw BindFailed("Failed to create socket");
206               }
207           
208               //
209               // Set the socket option SO_REUSEADDR to reuse the socket address so
210               // that we can rebind to a new socket using the same address when we
211               // need to resume the cimom as a result of a timeout during a Shutdown
212               // operation.
213               //
214               int opt=1;
215 mike  1.2     if (setsockopt(_rep->socket, SOL_SOCKET, SO_REUSEADDR,
216                            (char *)&opt, sizeof(opt)) < 0)
217               {
218                   delete _rep;
219                   _rep = 0;
220                   throw BindFailed("Failed to set socket option");
221               }
222           
223               // Bind socket to port:
224           
225               if (::bind(_rep->socket, 
226           	(struct sockaddr*)(void*)&_rep->address, 
227           	sizeof(_rep->address)) < 0)
228               {
229           	Socket::close(_rep->socket);
230           	delete _rep;
231           	_rep = 0;
232           	throw BindFailed("Failed to bind socket to port");
233               }
234           
235               // Set up listening on the given port:
236 mike  1.2 
237               int const MAX_CONNECTION_QUEUE_LENGTH = 5;
238           
239               if (listen(_rep->socket, MAX_CONNECTION_QUEUE_LENGTH) < 0)
240               {
241           	Socket::close(_rep->socket);
242           	delete _rep;
243           	_rep = 0;
244           	throw BindFailed("Failed to bind socket to port");
245               }
246           
247               // Register to receive SocketMessages on this socket:
248           
249               if (!_monitor->solicitSocketMessages(
250           	_rep->socket,
251           	SocketMessage::READ | SocketMessage::EXCEPTION,
252           	getQueueId()))
253               {
254           	Socket::close(_rep->socket);
255           	delete _rep;
256           	_rep = 0;
257 mike  1.2 	throw BindFailed("Failed to solicit socket messaeges");
258               }
259           }
260           
261           /**
262            closeConnectionSocket - close the server listening socket to disallow
263            new client connections.
264           */
265           void HTTPAcceptor::closeConnectionSocket()
266           {
267               if (_rep)
268               {
269                   // unregister the socket
270                   _monitor->unsolicitSocketMessages(_rep->socket);
271           
272                   // close the socket
273                   Socket::close(_rep->socket);
274               }
275           }
276           
277           /**
278 mike  1.2  reopenConnectionSocket - creates a new server socket.
279           */
280           void HTTPAcceptor::reopenConnectionSocket()
281           {
282               if (_rep)
283               {
284                   _bind();
285               }
286           }
287           
288           /**
289            getOutstandingRequestCount - returns the number of outstanding requests.
290           */
291           Uint32 HTTPAcceptor::getOutstandingRequestCount()
292           {
293               if (_rep->connections.size() > 0)
294               {
295                   HTTPConnection* connection = _rep->connections[0];	
296                   return(connection->getRequestCount());
297               }
298               else
299 mike  1.2     {
300                   return(0);
301               }
302           }
303           
304           void HTTPAcceptor::unbind()
305           {
306               if (_rep)
307               {
308           	Socket::close(_rep->socket);
309           	delete _rep;
310           	_rep = 0;
311               }
312           }
313           
314           void HTTPAcceptor::destroyConnections()
315           {
316               // For each connection created by this object:
317           
318               for (Uint32 i = 0, n = _rep->connections.size(); i < n; i++)
319               {
320 mike  1.2 	HTTPConnection* connection = _rep->connections[i];	
321           	Sint32 socket = connection->getSocket();
322           
323           	// Unsolicit SocketMessages:
324           
325           	_monitor->unsolicitSocketMessages(socket);
326           
327           	// Destroy the connection (causing it to close):
328           
329           	delete connection;
330               }
331           
332               _rep->connections.clear();
333           }
334           
335           void HTTPAcceptor::_acceptConnection()
336           {
337               // This function cannot be called on an invalid socket!
338           
339               PEGASUS_ASSERT(_rep != 0);
340           
341 mike  1.2     if (!_rep)
342           	return;
343           
344               // Accept the connection (populate the address):
345           
346               sockaddr_in address;
347           
348 sage  1.4 #if defined(PEGASUS_PLATFORM_ZOS_ZSERIES_IBM) || defined(PEGASUS_PLATFORM_AIX_RS_IBMCXX)
349 mike  1.2     size_t n = sizeof(address);
350           #else
351               int n = sizeof(address);
352           #endif
353           
354           #if defined(PEGASUS_PLATFORM_LINUX_IX86_GNU)    
355               Sint32 socket = accept(
356           	_rep->socket, (struct sockaddr*)&address, (socklen_t *)&n);
357           #else
358               Sint32 socket = accept(_rep->socket, (struct sockaddr*)&address, &n);
359           #endif
360           
361               if (socket < 0)
362               {
363           	if (getenv("PEGASUS_TRACE"))
364           	    cerr <<"HTTPAcceptor: accept() failed" << endl;
365           
366           	return;
367               }
368           
369               // Create a new conection and add it to the connection list:
370 mike  1.2 
371               MP_Socket * mp_socket = new MP_Socket(socket, _sslcontext);
372               if (mp_socket->accept() < 0) {
373           	if (getenv("PEGASUS_TRACE"))
374           	    cerr <<"HTTPAcceptor: SSL_accept() failed" << endl;
375           
376           	return;
377               }
378           
379               HTTPConnection* connection = new HTTPConnection(
380           	_monitor, mp_socket, this, _outputMessageQueue);
381           
382               // Solicit events on this new connection's socket:
383           
384               if (!_monitor->solicitSocketMessages(
385           	socket,
386           	SocketMessage::READ | SocketMessage::EXCEPTION,
387           	connection->getQueueId()))
388               {
389           	delete connection;
390           	Socket::close(socket);
391 mike  1.2     }
392           
393               // Save the socket for cleanup later:
394           
395               _rep->connections.append(connection);
396           }
397           
398           PEGASUS_NAMESPACE_END

No CVS admin address has been configured
Powered by
ViewCVS 0.9.2