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