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 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
59 PEGASUS_USING_STD;
60
61 PEGASUS_NAMESPACE_BEGIN
62
63 ////////////////////////////////////////////////////////////////////////////////
64 //
65 // HTTPAcceptorRep
66 //
67 ////////////////////////////////////////////////////////////////////////////////
68
69 struct HTTPAcceptorRep
70 {
|
71 kumpf 1.11 #ifdef PEGASUS_LOCAL_DOMAIN_SOCKET
72 struct sockaddr_un address;
73 #else
|
74 mday 1.7 struct sockaddr_in address;
|
75 kumpf 1.11 #endif
|
76 mday 1.7 Sint32 socket;
77 Array<HTTPConnection*> connections;
|
78 mike 1.2 };
79
80 ////////////////////////////////////////////////////////////////////////////////
81 //
82 // HTTPAcceptor
83 //
84 ////////////////////////////////////////////////////////////////////////////////
85
|
86 mday 1.9 HTTPAcceptor::HTTPAcceptor(Monitor* monitor, MessageQueueService* outputMessageQueue)
|
87 kumpf 1.15 : Base(PEGASUS_QUEUENAME_HTTPACCEPTOR),
|
88 mday 1.7 _monitor(monitor), _outputMessageQueue(outputMessageQueue),
89 _rep(0), _sslcontext(NULL)
|
90 mike 1.2 {
|
91 mday 1.5
|
92 mday 1.7 Socket::initializeInterface();
|
93 mike 1.2 }
94
|
95 mday 1.9 HTTPAcceptor::HTTPAcceptor(Monitor* monitor, MessageQueueService* outputMessageQueue,
|
96 mike 1.2 SSLContext * sslcontext)
|
97 kumpf 1.15 : Base(PEGASUS_QUEUENAME_HTTPACCEPTOR),
|
98 mday 1.16 _monitor(monitor), _outputMessageQueue(outputMessageQueue),
99 _rep(0),
|
100 mday 1.5 _sslcontext(sslcontext)
|
101 mike 1.2 {
|
102 mday 1.7 Socket::initializeInterface();
|
103 mike 1.2 }
104
105 HTTPAcceptor::~HTTPAcceptor()
106 {
|
107 mday 1.7 unbind();
108 Socket::uninitializeInterface();
|
109 mike 1.2 }
110
|
111 mday 1.7 void HTTPAcceptor::handleEnqueue(Message *message)
|
112 mike 1.2 {
|
113 mday 1.7 if (! message)
114 return;
115
116 switch (message->getType())
117 {
118 case SOCKET_MESSAGE:
119 {
120 SocketMessage* socketMessage = (SocketMessage*)message;
|
121 mday 1.16
|
122 mday 1.7 // If this is a connection request:
123
124 if (socketMessage->socket == _rep->socket &&
125 socketMessage->events | SocketMessage::READ)
126 {
127 _acceptConnection();
128 }
129 else
130 {
131 // ATTN! this can't happen!
132 }
133
134 break;
135 }
136
137 case CLOSE_CONNECTION_MESSAGE:
138 {
139 CloseConnectionMessage* closeConnectionMessage
140 = (CloseConnectionMessage*)message;
141
142 for (Uint32 i = 0, n = _rep->connections.size(); i < n; i++)
143 mday 1.7 {
144 HTTPConnection* connection = _rep->connections[i];
145 Sint32 socket = connection->getSocket();
|
146 mike 1.2
|
147 mday 1.7 if (socket == closeConnectionMessage->socket)
|
148 mike 1.2 {
|
149 mday 1.7 _monitor->unsolicitSocketMessages(socket);
150 _rep->connections.remove(i);
|
151 kumpf 1.17 while (connection->refcount.value()) { }
152 delete connection;
|
153 mday 1.7 break;
|
154 mike 1.2 }
|
155 mday 1.7 }
156 }
|
157 mike 1.2
|
158 kumpf 1.10 default:
159 // ATTN: need unexpected message error!
|
160 mday 1.7 break;
161 };
|
162 mike 1.2
|
163 mday 1.7 delete message;
164 }
|
165 mike 1.2
166
|
167 mday 1.7 void HTTPAcceptor::handleEnqueue()
168 {
169 Message* message = dequeue();
|
170 mike 1.2
|
171 mday 1.7 if (!message)
172 return;
173
174 handleEnqueue(message);
|
175 mike 1.2
176 }
177
178 void HTTPAcceptor::bind(Uint32 portNumber)
179 {
|
180 mday 1.7 if (_rep)
181 throw BindFailed("HTTPAcceptor already bound");
|
182 mike 1.2
|
183 mday 1.7 _rep = new HTTPAcceptorRep;
|
184 mike 1.2
|
185 mday 1.7 _portNumber = portNumber;
|
186 mike 1.2
|
187 mday 1.7 // bind address
188 _bind();
|
189 mike 1.2
|
190 mday 1.7 return;
|
191 mike 1.2 }
192
193 /**
|
194 mday 1.7 _bind - creates a new server socket and bind socket to the port address.
|
195 kumpf 1.11 If PEGASUS_LOCAL_DOMAIN_SOCKET is defined, the port number is ignored and
196 a domain socket is bound.
|
197 mike 1.2 */
198 void HTTPAcceptor::_bind()
199 {
200
|
201 mday 1.7 // Create address:
|
202 mike 1.2
|
203 mday 1.7 memset(&_rep->address, 0, sizeof(_rep->address));
|
204 kumpf 1.6
|
205 kumpf 1.11 #ifdef PEGASUS_LOCAL_DOMAIN_SOCKET
206 _rep->address.sun_family = AF_UNIX;
207 strcpy(_rep->address.sun_path, "/var/opt/wbem/cimxml.socket");
208 ::unlink(_rep->address.sun_path);
|
209 kumpf 1.6 #else
|
210 mday 1.7 _rep->address.sin_addr.s_addr = INADDR_ANY;
211 _rep->address.sin_family = AF_INET;
212 _rep->address.sin_port = htons(_portNumber);
|
213 kumpf 1.11 #endif
|
214 mike 1.2
|
215 mday 1.7 // Create socket:
|
216 mike 1.2
|
217 kumpf 1.11 #ifdef PEGASUS_LOCAL_DOMAIN_SOCKET
218 _rep->socket = socket(AF_UNIX, SOCK_STREAM, 0);
219 #else
|
220 mday 1.7 _rep->socket = socket(PF_INET, SOCK_STREAM, IPPROTO_TCP);
|
221 kumpf 1.11 #endif
|
222 mike 1.2
|
223 mday 1.7 if (_rep->socket < 0)
224 {
225 delete _rep;
226 _rep = 0;
227 throw BindFailed("Failed to create socket");
228 }
229
230 //
231 // Set the socket option SO_REUSEADDR to reuse the socket address so
232 // that we can rebind to a new socket using the same address when we
233 // need to resume the cimom as a result of a timeout during a Shutdown
234 // operation.
235 //
236 int opt=1;
237 if (setsockopt(_rep->socket, SOL_SOCKET, SO_REUSEADDR,
238 (char *)&opt, sizeof(opt)) < 0)
239 {
240 delete _rep;
241 _rep = 0;
242 throw BindFailed("Failed to set socket option");
243 }
244 mday 1.7
245 // Bind socket to port:
246
247 if (::bind(_rep->socket,
|
248 kumpf 1.10 reinterpret_cast<struct sockaddr*>(&_rep->address),
|
249 mday 1.7 sizeof(_rep->address)) < 0)
250 {
251 Socket::close(_rep->socket);
252 delete _rep;
253 _rep = 0;
|
254 kumpf 1.11 throw BindFailed("Failed to bind socket");
|
255 mday 1.7 }
256
|
257 kumpf 1.11 // Set up listening on the given socket:
|
258 mday 1.7
259 int const MAX_CONNECTION_QUEUE_LENGTH = 5;
260
261 if (listen(_rep->socket, MAX_CONNECTION_QUEUE_LENGTH) < 0)
262 {
263 Socket::close(_rep->socket);
264 delete _rep;
265 _rep = 0;
|
266 kumpf 1.11 throw BindFailed("Failed to bind socket");
|
267 mday 1.7 }
268
269 // Register to receive SocketMessages on this socket:
270
271 if (!_monitor->solicitSocketMessages(
272 _rep->socket,
273 SocketMessage::READ | SocketMessage::EXCEPTION,
|
274 mday 1.16 getQueueId(),
275 Monitor::ACCEPTOR))
|
276 mday 1.7 {
277 Socket::close(_rep->socket);
278 delete _rep;
279 _rep = 0;
280 throw BindFailed("Failed to solicit socket messaeges");
281 }
|
282 mike 1.2 }
283
284 /**
|
285 mday 1.7 closeConnectionSocket - close the server listening socket to disallow
286 new client connections.
|
287 mike 1.2 */
288 void HTTPAcceptor::closeConnectionSocket()
289 {
|
290 mday 1.7 if (_rep)
291 {
292 // unregister the socket
293 _monitor->unsolicitSocketMessages(_rep->socket);
294
295 // close the socket
296 Socket::close(_rep->socket);
297 }
|
298 mike 1.2 }
299
300 /**
|
301 mday 1.7 reopenConnectionSocket - creates a new server socket.
|
302 mike 1.2 */
303 void HTTPAcceptor::reopenConnectionSocket()
304 {
|
305 mday 1.7 if (_rep)
306 {
307 _bind();
308 }
|
309 mike 1.2 }
310
311 /**
|
312 mday 1.7 getOutstandingRequestCount - returns the number of outstanding requests.
|
313 mike 1.2 */
314 Uint32 HTTPAcceptor::getOutstandingRequestCount()
315 {
|
316 mday 1.7 if (_rep->connections.size() > 0)
317 {
318 HTTPConnection* connection = _rep->connections[0];
319 return(connection->getRequestCount());
320 }
321 else
322 {
323 return(0);
324 }
|
325 mike 1.2 }
326
327 void HTTPAcceptor::unbind()
328 {
|
329 mday 1.7 if (_rep)
330 {
331 Socket::close(_rep->socket);
332 delete _rep;
333 _rep = 0;
334 }
|
335 mike 1.2 }
336
337 void HTTPAcceptor::destroyConnections()
338 {
|
339 mday 1.7 // For each connection created by this object:
|
340 mike 1.2
|
341 mday 1.7 for (Uint32 i = 0, n = _rep->connections.size(); i < n; i++)
342 {
343 HTTPConnection* connection = _rep->connections[i];
344 Sint32 socket = connection->getSocket();
|
345 mike 1.2
|
346 mday 1.7 // Unsolicit SocketMessages:
|
347 mike 1.2
|
348 mday 1.7 _monitor->unsolicitSocketMessages(socket);
|
349 mike 1.2
|
350 mday 1.7 // Destroy the connection (causing it to close):
|
351 mike 1.2
|
352 kumpf 1.17 while (connection->refcount.value()) { }
|
353 mday 1.7 delete connection;
354 }
|
355 mike 1.2
|
356 mday 1.7 _rep->connections.clear();
|
357 mike 1.2 }
358
359 void HTTPAcceptor::_acceptConnection()
360 {
|
361 mday 1.7 // This function cannot be called on an invalid socket!
|
362 mike 1.2
|
363 mday 1.7 PEGASUS_ASSERT(_rep != 0);
|
364 mike 1.2
|
365 mday 1.7 if (!_rep)
366 return;
|
367 mike 1.2
|
368 mday 1.7 // Accept the connection (populate the address):
|
369 mike 1.2
|
370 mday 1.7 sockaddr_in address;
|
371 mike 1.2
|
372 sage 1.4 #if defined(PEGASUS_PLATFORM_ZOS_ZSERIES_IBM) || defined(PEGASUS_PLATFORM_AIX_RS_IBMCXX)
|
373 mday 1.7 size_t n = sizeof(address);
|
374 mike 1.2 #else
|
375 mday 1.7 int n = sizeof(address);
|
376 mike 1.2 #endif
377
|
378 kumpf 1.14 #if defined(PEGASUS_PLATFORM_LINUX_IX86_GNU) || defined(PEGASUS_PLATFORM_LINUX_GENERIC_GNU)
|
379 mday 1.7 Sint32 socket = accept(
380 _rep->socket, (struct sockaddr*)&address, (socklen_t *)&n);
|
381 mike 1.2 #else
|
382 kumpf 1.10 Sint32 socket = accept(_rep->socket, reinterpret_cast<struct sockaddr*>(&address), &n);
|
383 mike 1.2 #endif
384
|
385 mday 1.7 if (socket < 0)
386 {
387 if (getenv("PEGASUS_TRACE"))
388 cerr <<"HTTPAcceptor: accept() failed" << endl;
|
389 mike 1.2
|
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 if (mp_socket->accept() < 0) {
397 if (getenv("PEGASUS_TRACE"))
398 cerr <<"HTTPAcceptor: SSL_accept() failed" << endl;
|
399 mike 1.2
|
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 mike 1.2
|
408 mday 1.7 if (!_monitor->solicitSocketMessages(
409 socket,
410 SocketMessage::READ | SocketMessage::EXCEPTION,
|
411 mday 1.16 connection->getQueueId(), Monitor::CONNECTION))
|
412 mday 1.7 {
413 delete connection;
414 Socket::close(socket);
415 }
|
416 mike 1.2
|
417 mday 1.7 // Save the socket for cleanup later:
|
418 mike 1.2
|
419 mday 1.7 _rep->connections.append(connection);
|
420 mike 1.2 }
421
422 PEGASUS_NAMESPACE_END
|