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 mike 1.1.2.4 HTTPAcceptor::HTTPAcceptor(Monitor* monitor, MessageQueue* outputMessageQueue)
76 : _monitor(monitor), _outputMessageQueue(outputMessageQueue), _rep(0)
|
77 mike 1.1.2.1 {
|
78 mike 1.1.2.6 Socket::initializeInterface();
|
79 mike 1.1.2.1 }
80
81 HTTPAcceptor::~HTTPAcceptor()
82 {
83 unbind();
|
84 mike 1.1.2.6 Socket::uninitializeInterface();
|
85 mike 1.1.2.1 }
86
87 void HTTPAcceptor::handleEnqueue()
88 {
|
89 mike 1.1.2.5 // cout << "HTTPAcceptor::handleEnqueue()" << endl;
|
90 mike 1.1.2.1
91 Message* message = dequeue();
92
93 if (!message)
94 return;
95
96 switch (message->getType())
97 {
98 case SOCKET_MESSAGE:
99 {
100 SocketMessage* socketMessage = (SocketMessage*)message;
101
102 // If this is a connection request:
103
104 if (socketMessage->socket == _rep->socket &&
105 socketMessage->events | SocketMessage::READ)
106 {
107 _acceptConnection();
108 }
109 else
110 {
111 mike 1.1.2.1 // ATTN! this can't happen!
112 }
113
114 break;
115 }
116
117 case CLOSE_CONNECTION_MESSAGE:
118 {
119 CloseConnectionMessage* closeConnectionMessage
120 = (CloseConnectionMessage*)message;
121
122 for (Uint32 i = 0, n = _rep->connections.size(); i < n; i++)
123 {
124 HTTPConnection* connection = _rep->connections[i];
125 Sint32 socket = connection->getSocket();
126
127 if (socket == closeConnectionMessage->socket)
128 {
129 _monitor->unsolicitSocketMessages(socket);
130 _rep->connections.remove(i);
131 delete connection;
132 mike 1.1.2.1 break;
133 }
134 }
135 }
136
137 default:
138 // ATTN: need unexpected message error!
139 break;
140 };
141
142 delete message;
|
143 mike 1.1.2.7 }
144
145 const char* HTTPAcceptor::getQueueName() const
146 {
147 return "HTTPAcceptor";
|
148 mike 1.1.2.1 }
149
150 void HTTPAcceptor::bind(Uint32 portNumber)
151 {
152 if (_rep)
153 throw BindFailed("HTTPAcceptor already bound");
154
155 _rep = new HTTPAcceptorRep;
156
157 // Create address:
158
159 memset(&_rep->address, 0, sizeof(_rep->address));
160 _rep->address.sin_addr.s_addr = INADDR_ANY;
161 _rep->address.sin_family = AF_INET;
162 _rep->address.sin_port = htons(portNumber);
163
164 // Create socket:
165
166 _rep->socket = socket(PF_INET, SOCK_STREAM, IPPROTO_TCP);
167
168 if (_rep->socket < 0)
169 mike 1.1.2.1 {
170 delete _rep;
171 _rep = 0;
172 throw BindFailed("Failed to create socket");
173 }
174
175 // Bind socket to port:
176
177 if (::bind(_rep->socket,
178 (struct sockaddr*)(void*)&_rep->address,
179 sizeof(_rep->address)) < 0)
180 {
181 Socket::close(_rep->socket);
182 delete _rep;
183 _rep = 0;
184 throw BindFailed("Failed to bind socket to port");
185 }
186
187 // Set up listening on the given port:
188
189 int const MAX_CONNECTION_QUEUE_LENGTH = 5;
190 mike 1.1.2.1
191 if (listen(_rep->socket, MAX_CONNECTION_QUEUE_LENGTH) < 0)
192 {
193 Socket::close(_rep->socket);
194 delete _rep;
195 _rep = 0;
196 throw BindFailed("Failed to bind socket to port");
197 }
198
199 // Register to receive SocketMessages on this socket:
200
201 if (!_monitor->solicitSocketMessages(
202 _rep->socket,
203 SocketMessage::READ | SocketMessage::EXCEPTION,
204 getQueueId()))
205 {
206 Socket::close(_rep->socket);
207 delete _rep;
208 _rep = 0;
209 throw BindFailed("Failed to solicit socket messaeges");
210 }
211 mike 1.1.2.1 }
212
213 void HTTPAcceptor::unbind()
214 {
215 if (_rep)
216 {
217 Socket::close(_rep->socket);
218 delete _rep;
219 _rep = 0;
220 }
221 }
222
223 void HTTPAcceptor::destroyConnections()
224 {
225 // For each connection created by this object:
226
227 for (Uint32 i = 0, n = _rep->connections.size(); i < n; i++)
228 {
229 HTTPConnection* connection = _rep->connections[i];
230 Sint32 socket = connection->getSocket();
231
232 mike 1.1.2.1 // Unsolicit SocketMessages:
233
234 _monitor->unsolicitSocketMessages(socket);
235
236 // Destroy the connection (causing it to close):
237
238 delete connection;
239 }
240
241 _rep->connections.clear();
242 }
243
244 void HTTPAcceptor::_acceptConnection()
245 {
246 // This function cannot be called on an invalid socket!
247
248 PEGASUS_ASSERT(_rep != 0);
249
250 if (!_rep)
251 return;
252
253 mike 1.1.2.1 // Accept the connection (populate the address):
254
255 sockaddr_in address;
256 int n = sizeof(address);
|
257 mday 1.1.2.2 #if defined(PEGASUS_PLATFORM_LINUX_IX86_GNU)
|
258 mike 1.1.2.3 Sint32 socket = accept(
259 _rep->socket, (struct sockaddr*)&address, (socklen_t *)&n);
|
260 mday 1.1.2.2 #else
|
261 mike 1.1.2.1 Sint32 socket = accept(_rep->socket, (struct sockaddr*)&address, &n);
|
262 mday 1.1.2.2 #endif
|
263 mike 1.1.2.1
264 if (socket < 0)
265 {
266 if (getenv("PEGASUS_TRACE"))
267 cerr <<"HTTPAcceptor: accept() failed" << endl;
268
269 return;
270 }
271
272 // Create a new conection and add it to the connection list:
273
|
274 mike 1.1.2.4 HTTPConnection* connection = new HTTPConnection(
|
275 mike 1.1.2.5 _monitor, socket, this, _outputMessageQueue);
|
276 mike 1.1.2.1
|
277 mike 1.1.2.6 // Solicit events on this new connection's socket:
|
278 mike 1.1.2.1
279 if (!_monitor->solicitSocketMessages(
280 socket,
281 SocketMessage::READ | SocketMessage::EXCEPTION,
282 connection->getQueueId()))
283 {
284 delete connection;
285 Socket::close(socket);
286 }
287
288 // Save the socket for cleanup later:
289
290 _rep->connections.append(connection);
291 }
292
293 PEGASUS_NAMESPACE_END
|