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
|