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

  1 mike  1.1.2.1 //%/////////////////////////////////////////////////////////////////////////////
  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.1.2.1 //==============================================================================
 23               //
 24               // Author: Mike Brasher (mbrasher@bmc.com)
 25               //
 26               // Modified By:
 27               //
 28               //%/////////////////////////////////////////////////////////////////////////////
 29               
 30               #include <iostream>
 31               #include "Config.h"
 32               #include "Socket.h"
 33               
 34               #ifdef PEGASUS_OS_TYPE_WINDOWS
 35               # include <winsock.h>
 36               #else
 37               # include <cctype>
 38               # include <unistd.h>
 39               # include <cstdlib>
 40               # include <errno.h>
 41               # include <fcntl.h>
 42               # include <netdb.h>
 43 mike  1.1.2.1 # include <netinet/in.h>
 44               # include <arpa/inet.h>
 45               # include <sys/socket.h>
 46               #endif
 47               
 48               #include "Socket.h"
 49               #include "HTTPAcceptor.h"
 50               #include "HTTPConnection.h"
 51               
 52               PEGASUS_USING_STD;
 53               
 54               PEGASUS_NAMESPACE_BEGIN
 55               
 56               ////////////////////////////////////////////////////////////////////////////////
 57               //
 58               // HTTPAcceptorRep
 59               //
 60               ////////////////////////////////////////////////////////////////////////////////
 61               
 62               struct HTTPAcceptorRep
 63               {
 64 mike  1.1.2.1     struct sockaddr_in address;
 65                   Sint32 socket;
 66                   Array<HTTPConnection*> connections;
 67               };
 68               
 69               ////////////////////////////////////////////////////////////////////////////////
 70               //
 71               // HTTPAcceptor
 72               //
 73               ////////////////////////////////////////////////////////////////////////////////
 74               
 75               HTTPAcceptor::HTTPAcceptor(Monitor* monitor) : _monitor(monitor), _rep(0)
 76               {
 77                   // Note: we are counting on the monitor to initialize the socket
 78                   // interface (in Windows you have to call WSAInitialize() and
 79                   // WSAShutDown()).
 80               }
 81               
 82               HTTPAcceptor::~HTTPAcceptor()
 83               {
 84                   unbind();
 85 mike  1.1.2.1 }
 86               
 87               void HTTPAcceptor::handleEnqueue()
 88               {
 89                   cout << "HTTPAcceptor::handleEnqueue()" << endl;
 90               
 91                   Message* message = dequeue();
 92               
 93                   if (!message)
 94                       return;
 95               
 96                   if (getenv("PEGASUS_TRACE"))
 97                       message->print(cout);
 98               
 99                   switch (message->getType())
100                   {
101               	case SOCKET_MESSAGE:
102               	{
103               	    SocketMessage* socketMessage = (SocketMessage*)message;
104               
105               	    // If this is a connection request:
106 mike  1.1.2.1 
107               	    if (socketMessage->socket == _rep->socket &&
108               		socketMessage->events | SocketMessage::READ)
109               	    {
110               		_acceptConnection();
111               	    }
112               	    else
113               	    {
114               		// ATTN! this can't happen!
115               	    }
116               
117               	    break;
118               	}
119               
120               	case CLOSE_CONNECTION_MESSAGE:
121               	{
122               	    CloseConnectionMessage* closeConnectionMessage 
123               		= (CloseConnectionMessage*)message;
124               
125               	    for (Uint32 i = 0, n = _rep->connections.size(); i < n; i++)
126               	    {
127 mike  1.1.2.1 		HTTPConnection* connection = _rep->connections[i];	
128               		Sint32 socket = connection->getSocket();
129               
130               		if (socket == closeConnectionMessage->socket)
131               		{
132               		    _monitor->unsolicitSocketMessages(socket);
133               		    _rep->connections.remove(i);
134               		    delete connection;
135               		    break;
136               		}
137               	    }
138               	}
139               
140               	default:
141               	    // ATTN: need unexpected message error!
142               	    break;
143                   };
144               
145                   delete message;
146               }
147               
148 mike  1.1.2.1 void HTTPAcceptor::bind(Uint32 portNumber)
149               {
150                   if (_rep)
151               	throw BindFailed("HTTPAcceptor already bound");
152               
153                   _rep = new HTTPAcceptorRep;
154               
155                   // Create address:
156               
157                   memset(&_rep->address, 0, sizeof(_rep->address));
158                   _rep->address.sin_addr.s_addr = INADDR_ANY;
159                   _rep->address.sin_family = AF_INET;
160                   _rep->address.sin_port = htons(portNumber);
161               
162                   // Create socket:
163                   
164                   _rep->socket = socket(PF_INET, SOCK_STREAM, IPPROTO_TCP);
165               
166                   if (_rep->socket < 0)
167                   {
168               	delete _rep;
169 mike  1.1.2.1 	_rep = 0;
170               	throw BindFailed("Failed to create socket");
171                   }
172               
173                   // Bind socket to port:
174               
175                   if (::bind(_rep->socket, 
176               	(struct sockaddr*)(void*)&_rep->address, 
177               	sizeof(_rep->address)) < 0)
178                   {
179               	Socket::close(_rep->socket);
180               	delete _rep;
181               	_rep = 0;
182               	throw BindFailed("Failed to bind socket to port");
183                   }
184               
185                   // Set up listening on the given port:
186               
187                   int const MAX_CONNECTION_QUEUE_LENGTH = 5;
188               
189                   if (listen(_rep->socket, MAX_CONNECTION_QUEUE_LENGTH) < 0)
190 mike  1.1.2.1     {
191               	Socket::close(_rep->socket);
192               	delete _rep;
193               	_rep = 0;
194               	throw BindFailed("Failed to bind socket to port");
195                   }
196               
197                   // Register to receive SocketMessages on this socket:
198               
199                   if (!_monitor->solicitSocketMessages(
200               	_rep->socket,
201               	SocketMessage::READ | SocketMessage::EXCEPTION,
202               	getQueueId()))
203                   {
204               	Socket::close(_rep->socket);
205               	delete _rep;
206               	_rep = 0;
207               	throw BindFailed("Failed to solicit socket messaeges");
208                   }
209               }
210               
211 mike  1.1.2.1 void HTTPAcceptor::unbind()
212               {
213                   if (_rep)
214                   {
215               	Socket::close(_rep->socket);
216               	delete _rep;
217               	_rep = 0;
218                   }
219               }
220               
221               void HTTPAcceptor::destroyConnections()
222               {
223                   // For each connection created by this object:
224               
225                   for (Uint32 i = 0, n = _rep->connections.size(); i < n; i++)
226                   {
227               	HTTPConnection* connection = _rep->connections[i];	
228               	Sint32 socket = connection->getSocket();
229               
230               	// Unsolicit SocketMessages:
231               
232 mike  1.1.2.1 	_monitor->unsolicitSocketMessages(socket);
233               
234               	// Destroy the connection (causing it to close):
235               
236               	delete connection;
237                   }
238               
239                   _rep->connections.clear();
240               }
241               
242               void HTTPAcceptor::_acceptConnection()
243               {
244                   // This function cannot be called on an invalid socket!
245               
246                   PEGASUS_ASSERT(_rep != 0);
247               
248                   if (!_rep)
249               	return;
250               
251                   // Accept the connection (populate the address):
252               
253 mike  1.1.2.1     sockaddr_in address;
254                   int n = sizeof(address);
255                   Sint32 socket = accept(_rep->socket, (struct sockaddr*)&address, &n);
256               
257                   if (socket < 0)
258                   {
259               	if (getenv("PEGASUS_TRACE"))
260               	    cerr <<"HTTPAcceptor: accept() failed" << endl;
261               
262               	return;
263                   }
264               
265                   // Create a new conection and add it to the connection list:
266               
267                   HTTPConnection* connection = new HTTPConnection(socket, this);
268               
269                   // Solicit events on this new connection socket:
270               
271                   if (!_monitor->solicitSocketMessages(
272               	socket,
273               	SocketMessage::READ | SocketMessage::EXCEPTION,
274 mike  1.1.2.1 	connection->getQueueId()))
275                   {
276               	delete connection;
277               	Socket::close(socket);
278                   }
279               
280                   // Save the socket for cleanup later:
281               
282                   _rep->connections.append(connection);
283               }
284               
285               PEGASUS_NAMESPACE_END

No CVS admin address has been configured
Powered by
ViewCVS 0.9.2