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
|