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.23.2.1 Mutex _connection_mut;
78
|
79 mday 1.7 Sint32 socket;
80 Array<HTTPConnection*> connections;
|
81 mike 1.2 };
82
83 ////////////////////////////////////////////////////////////////////////////////
84 //
85 // HTTPAcceptor
86 //
87 ////////////////////////////////////////////////////////////////////////////////
88
|
89 kumpf 1.18 HTTPAcceptor::HTTPAcceptor(Monitor* monitor, MessageQueue* outputMessageQueue)
|
90 kumpf 1.15 : Base(PEGASUS_QUEUENAME_HTTPACCEPTOR),
|
91 mday 1.7 _monitor(monitor), _outputMessageQueue(outputMessageQueue),
|
92 mday 1.21 _rep(0), _sslcontext(NULL), _entry_index(-1)
|
93 mike 1.2 {
|
94 mday 1.5
|
95 mday 1.23.2.1 _inet_address[0] = 0x00;
|
96 mday 1.7 Socket::initializeInterface();
|
97 mike 1.2 }
98
|
99 kumpf 1.18 HTTPAcceptor::HTTPAcceptor(Monitor* monitor, MessageQueue* outputMessageQueue,
|
100 mike 1.2 SSLContext * sslcontext)
|
101 kumpf 1.15 : Base(PEGASUS_QUEUENAME_HTTPACCEPTOR),
|
102 mday 1.16 _monitor(monitor), _outputMessageQueue(outputMessageQueue),
103 _rep(0),
|
104 mday 1.21 _sslcontext(sslcontext),
105 _entry_index(-1)
|
106 mike 1.2 {
|
107 mday 1.23.2.1 _inet_address[0] = 0x00;
108 Socket::initializeInterface();
109 }
110
111 HTTPAcceptor::HTTPAcceptor(Monitor* monitor, MessageQueue* outputMessageQueue,
112 SSLContext * sslcontext,
113 char *inet_address)
114 : Base(PEGASUS_QUEUENAME_HTTPACCEPTOR),
115 _monitor(monitor), _outputMessageQueue(outputMessageQueue),
116 _rep(0),
117 _sslcontext(sslcontext),
118 _entry_index(-1)
119 {
120 strncpy(_inet_address, inet_address, 16);
121 _inet_address[16] = 0x00;
|
122 mday 1.7 Socket::initializeInterface();
|
123 mike 1.2 }
124
125 HTTPAcceptor::~HTTPAcceptor()
126 {
|
127 mday 1.7 unbind();
128 Socket::uninitializeInterface();
|
129 mike 1.2 }
130
|
131 mday 1.7 void HTTPAcceptor::handleEnqueue(Message *message)
|
132 mike 1.2 {
|
133 mday 1.7 if (! message)
134 return;
135
136 switch (message->getType())
137 {
138 case SOCKET_MESSAGE:
139 {
140 SocketMessage* socketMessage = (SocketMessage*)message;
|
141 mday 1.16
|
142 mday 1.7 // If this is a connection request:
143
144 if (socketMessage->socket == _rep->socket &&
145 socketMessage->events | SocketMessage::READ)
146 {
147 _acceptConnection();
148 }
149 else
150 {
151 // ATTN! this can't happen!
152 }
153
154 break;
155 }
156
157 case CLOSE_CONNECTION_MESSAGE:
158 {
159 CloseConnectionMessage* closeConnectionMessage
160 = (CloseConnectionMessage*)message;
161
|
162 mday 1.23.2.1 _rep->_connection_mut.lock(pegasus_thread_self());
163
|
164 mday 1.7 for (Uint32 i = 0, n = _rep->connections.size(); i < n; i++)
165 {
166 HTTPConnection* connection = _rep->connections[i];
167 Sint32 socket = connection->getSocket();
|
168 mday 1.23.2.1
|
169 mday 1.7 if (socket == closeConnectionMessage->socket)
|
170 mike 1.2 {
|
171 mday 1.7 _monitor->unsolicitSocketMessages(socket);
172 _rep->connections.remove(i);
|
173 kumpf 1.17 delete connection;
|
174 mday 1.23.2.1 PEGASUS_STD(cout) << "Closing HTTP Connection; Current Connection Table Size: " <<
175 _rep->connections.size() << PEGASUS_STD(endl);
|
176 mday 1.7 break;
|
177 mike 1.2 }
|
178 mday 1.7 }
|
179 mday 1.23.2.1 _rep->_connection_mut.unlock();
180
|
181 mday 1.7 }
|
182 mike 1.2
|
183 kumpf 1.10 default:
184 // ATTN: need unexpected message error!
|
185 mday 1.7 break;
186 };
|
187 mike 1.2
|
188 mday 1.7 delete message;
189 }
|
190 mike 1.2
191
|
192 mday 1.7 void HTTPAcceptor::handleEnqueue()
193 {
194 Message* message = dequeue();
|
195 mike 1.2
|
196 mday 1.7 if (!message)
197 return;
198
199 handleEnqueue(message);
|
200 mike 1.2
201 }
202
203 void HTTPAcceptor::bind(Uint32 portNumber)
204 {
|
205 mday 1.7 if (_rep)
|
206 kumpf 1.23 throw BindFailedException("HTTPAcceptor already bound");
|
207 mike 1.2
|
208 mday 1.7 _rep = new HTTPAcceptorRep;
|
209 mike 1.2
|
210 mday 1.7 _portNumber = portNumber;
|
211 mike 1.2
|
212 mday 1.7 // bind address
213 _bind();
|
214 mike 1.2
|
215 mday 1.7 return;
|
216 mike 1.2 }
217
218 /**
|
219 mday 1.7 _bind - creates a new server socket and bind socket to the port address.
|
220 kumpf 1.11 If PEGASUS_LOCAL_DOMAIN_SOCKET is defined, the port number is ignored and
221 a domain socket is bound.
|
222 mike 1.2 */
223 void HTTPAcceptor::_bind()
224 {
225
|
226 mday 1.7 // Create address:
|
227 mike 1.2
|
228 mday 1.7 memset(&_rep->address, 0, sizeof(_rep->address));
|
229 kumpf 1.6
|
230 kumpf 1.11 #ifdef PEGASUS_LOCAL_DOMAIN_SOCKET
231 _rep->address.sun_family = AF_UNIX;
232 strcpy(_rep->address.sun_path, "/var/opt/wbem/cimxml.socket");
233 ::unlink(_rep->address.sun_path);
|
234 kumpf 1.6 #else
|
235 mday 1.23.2.1 if(_inet_address[0] != 0x00)
236 {
237 _rep->address.sin_addr.s_addr = inet_addr(_inet_address);
238 cout << "binding to " << _inet_address << endl;
239
240 }
241 else
242 {
243 _rep->address.sin_addr.s_addr = INADDR_ANY;
244 }
245
|
246 mday 1.7 _rep->address.sin_family = AF_INET;
247 _rep->address.sin_port = htons(_portNumber);
|
248 kumpf 1.11 #endif
|
249 mike 1.2
|
250 mday 1.7 // Create socket:
|
251 mike 1.2
|
252 kumpf 1.11 #ifdef PEGASUS_LOCAL_DOMAIN_SOCKET
253 _rep->socket = socket(AF_UNIX, SOCK_STREAM, 0);
254 #else
|
255 mday 1.7 _rep->socket = socket(PF_INET, SOCK_STREAM, IPPROTO_TCP);
|
256 kumpf 1.11 #endif
|
257 mike 1.2
|
258 mday 1.7 if (_rep->socket < 0)
259 {
260 delete _rep;
261 _rep = 0;
|
262 kumpf 1.23 throw BindFailedException("Failed to create socket");
|
263 mday 1.7 }
264
265 //
266 // Set the socket option SO_REUSEADDR to reuse the socket address so
267 // that we can rebind to a new socket using the same address when we
268 // need to resume the cimom as a result of a timeout during a Shutdown
269 // operation.
270 //
271 int opt=1;
272 if (setsockopt(_rep->socket, SOL_SOCKET, SO_REUSEADDR,
273 (char *)&opt, sizeof(opt)) < 0)
274 {
275 delete _rep;
276 _rep = 0;
|
277 kumpf 1.23 throw BindFailedException("Failed to set socket option");
|
278 mday 1.7 }
279
280 // Bind socket to port:
281
282 if (::bind(_rep->socket,
|
283 kumpf 1.10 reinterpret_cast<struct sockaddr*>(&_rep->address),
|
284 mday 1.7 sizeof(_rep->address)) < 0)
285 {
286 Socket::close(_rep->socket);
287 delete _rep;
288 _rep = 0;
|
289 kumpf 1.23 throw BindFailedException("Failed to bind socket");
|
290 mday 1.7 }
291
|
292 kumpf 1.11 // Set up listening on the given socket:
|
293 mday 1.7
294 int const MAX_CONNECTION_QUEUE_LENGTH = 5;
295
296 if (listen(_rep->socket, MAX_CONNECTION_QUEUE_LENGTH) < 0)
297 {
298 Socket::close(_rep->socket);
299 delete _rep;
300 _rep = 0;
|
301 kumpf 1.23 throw BindFailedException("Failed to bind socket");
|
302 mday 1.7 }
303
304 // Register to receive SocketMessages on this socket:
305
|
306 mday 1.21 if ( -1 == ( _entry_index = _monitor->solicitSocketMessages(
|
307 mday 1.7 _rep->socket,
308 SocketMessage::READ | SocketMessage::EXCEPTION,
|
309 mday 1.16 getQueueId(),
|
310 mday 1.21 Monitor::ACCEPTOR)))
|
311 mday 1.7 {
312 Socket::close(_rep->socket);
313 delete _rep;
314 _rep = 0;
|
315 kumpf 1.23 throw BindFailedException("Failed to solicit socket messaeges");
|
316 mday 1.7 }
|
317 mike 1.2 }
318
319 /**
|
320 mday 1.7 closeConnectionSocket - close the server listening socket to disallow
321 new client connections.
|
322 mike 1.2 */
323 void HTTPAcceptor::closeConnectionSocket()
324 {
|
325 mday 1.7 if (_rep)
326 {
327 // unregister the socket
328 _monitor->unsolicitSocketMessages(_rep->socket);
329
330 // close the socket
331 Socket::close(_rep->socket);
332 }
|
333 mike 1.2 }
334
335 /**
|
336 mday 1.7 reopenConnectionSocket - creates a new server socket.
|
337 mike 1.2 */
338 void HTTPAcceptor::reopenConnectionSocket()
339 {
|
340 mday 1.7 if (_rep)
341 {
342 _bind();
343 }
|
344 mike 1.2 }
345
346 /**
|
347 mday 1.7 getOutstandingRequestCount - returns the number of outstanding requests.
|
348 mike 1.2 */
349 Uint32 HTTPAcceptor::getOutstandingRequestCount()
350 {
|
351 mday 1.23.2.1 Uint32 count = 0;
352
353 _rep->_connection_mut.lock(pegasus_thread_self());
|
354 mday 1.7 if (_rep->connections.size() > 0)
355 {
356 HTTPConnection* connection = _rep->connections[0];
|
357 mday 1.23.2.1 count = connection->getRequestCount();
|
358 mday 1.7 }
|
359 mday 1.23.2.1 _rep->_connection_mut.unlock();
360 return count;
361
|
362 mike 1.2 }
363
364 void HTTPAcceptor::unbind()
365 {
|
366 mday 1.7 if (_rep)
367 {
368 Socket::close(_rep->socket);
369 delete _rep;
370 _rep = 0;
371 }
|
372 mike 1.2 }
373
374 void HTTPAcceptor::destroyConnections()
375 {
|
376 mday 1.7 // For each connection created by this object:
|
377 mike 1.2
|
378 mday 1.23.2.1 _rep->_connection_mut.lock(pegasus_thread_self());
|
379 mday 1.7 for (Uint32 i = 0, n = _rep->connections.size(); i < n; i++)
380 {
381 HTTPConnection* connection = _rep->connections[i];
382 Sint32 socket = connection->getSocket();
|
383 mike 1.2
|
384 mday 1.7 // Unsolicit SocketMessages:
|
385 mike 1.2
|
386 mday 1.7 _monitor->unsolicitSocketMessages(socket);
|
387 mike 1.2
|
388 mday 1.7 // Destroy the connection (causing it to close):
|
389 mike 1.2
|
390 kumpf 1.17 while (connection->refcount.value()) { }
|
391 mday 1.7 delete connection;
392 }
|
393 mike 1.2
|
394 mday 1.7 _rep->connections.clear();
|
395 mday 1.23.2.1 _rep->_connection_mut.unlock();
|
396 mike 1.2 }
397
398 void HTTPAcceptor::_acceptConnection()
399 {
|
400 mday 1.7 // This function cannot be called on an invalid socket!
|
401 mike 1.2
|
402 mday 1.7 PEGASUS_ASSERT(_rep != 0);
|
403 mike 1.2
|
404 mday 1.7 if (!_rep)
405 return;
|
406 mike 1.2
|
407 mday 1.7 // Accept the connection (populate the address):
|
408 mike 1.2
|
409 mday 1.7 sockaddr_in address;
|
410 mike 1.2
|
411 sage 1.4 #if defined(PEGASUS_PLATFORM_ZOS_ZSERIES_IBM) || defined(PEGASUS_PLATFORM_AIX_RS_IBMCXX)
|
412 mday 1.7 size_t n = sizeof(address);
|
413 mike 1.2 #else
|
414 mday 1.7 int n = sizeof(address);
|
415 mike 1.2 #endif
416
|
417 mday 1.23.2.1
|
418 kumpf 1.14 #if defined(PEGASUS_PLATFORM_LINUX_IX86_GNU) || defined(PEGASUS_PLATFORM_LINUX_GENERIC_GNU)
|
419 mday 1.7 Sint32 socket = accept(
420 _rep->socket, (struct sockaddr*)&address, (socklen_t *)&n);
|
421 mike 1.2 #else
|
422 kumpf 1.10 Sint32 socket = accept(_rep->socket, reinterpret_cast<struct sockaddr*>(&address), &n);
|
423 mike 1.2 #endif
424
|
425 mday 1.23.2.1
426
|
427 mday 1.7 if (socket < 0)
428 {
|
429 kumpf 1.19 PEG_TRACE_STRING(TRC_HTTP, Tracer::LEVEL2,
430 "HTTPAcceptor: accept() failed");
|
431 mday 1.7 return;
432 }
|
433 mday 1.23.2.1 #if defined(PEGASUS_PLATFORM_LINUX_IX86_GNU) || defined(PEGASUS_PLATFORM_LINUX_GENERIC_GNU)
434 if( _inet_address[0] != 0x00)
435 {
436 if( 1023 < htons(address.sin_port) )
437 {
438 shutdown(socket, 2);
439 Socket::close(socket);
440 return;
441 }
442 }
443
444 #endif
|
445 mday 1.7 // Create a new conection and add it to the connection list:
|
446 mike 1.2
|
447 mday 1.7 MP_Socket * mp_socket = new MP_Socket(socket, _sslcontext);
|
448 kumpf 1.19 if (mp_socket->accept() < 0)
449 {
450 PEG_TRACE_STRING(TRC_HTTP, Tracer::LEVEL2,
451 "HTTPAcceptor: SSL_accept() failed");
|
452 mday 1.7 return;
453 }
|
454 mike 1.2
|
455 mday 1.7 HTTPConnection* connection = new HTTPConnection(
|
456 mday 1.16 _monitor, mp_socket, this, static_cast<MessageQueue *>(_outputMessageQueue));
|
457 mike 1.2
|
458 mday 1.7 // Solicit events on this new connection's socket:
|
459 mday 1.21 int index;
460
|
461 mday 1.23.2.1 if (! (index = _monitor->solicitSocketMessages(
|
462 mday 1.7 socket,
463 SocketMessage::READ | SocketMessage::EXCEPTION,
|
464 mday 1.21 connection->getQueueId(), Monitor::CONNECTION)) )
|
465 mday 1.7 {
466 delete connection;
467 Socket::close(socket);
468 }
|
469 mike 1.2
|
470 mday 1.7 // Save the socket for cleanup later:
|
471 mday 1.21 connection->_entry_index = index;
|
472 mday 1.23.2.1 _rep->_connection_mut.lock(pegasus_thread_self());
|
473 mday 1.7 _rep->connections.append(connection);
|
474 mday 1.23.2.1 _rep->_connection_mut.unlock();
475 PEGASUS_STD(cout) << "Creating new HTTP Connection; Current Connection Table Size: " <<
476 _rep->connections.size() << " entries" << endl;
477
|
478 mike 1.2 }
479
480 PEGASUS_NAMESPACE_END
|