1 karl 1.91 //%2006////////////////////////////////////////////////////////////////////////
2 //
3 // Copyright (c) 2000, 2001, 2002 BMC Software; Hewlett-Packard Development
4 // Company, L.P.; IBM Corp.; The Open Group; Tivoli Systems.
5 // Copyright (c) 2003 BMC Software; Hewlett-Packard Development Company, L.P.;
6 // IBM Corp.; EMC Corporation, The Open Group.
7 // Copyright (c) 2004 BMC Software; Hewlett-Packard Development Company, L.P.;
8 // IBM Corp.; EMC Corporation; VERITAS Software Corporation; The Open Group.
9 // Copyright (c) 2005 Hewlett-Packard Development Company, L.P.; IBM Corp.;
10 // EMC Corporation; VERITAS Software Corporation; The Open Group.
11 // Copyright (c) 2006 Hewlett-Packard Development Company, L.P.; IBM Corp.;
12 // EMC Corporation; Symantec Corporation; The Open Group.
13 //
14 // Permission is hereby granted, free of charge, to any person obtaining a copy
15 // of this software and associated documentation files (the "Software"), to
16 // deal in the Software without restriction, including without limitation the
17 // rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
18 // sell copies of the Software, and to permit persons to whom the Software is
19 // furnished to do so, subject to the following conditions:
20 //
21 // THE ABOVE COPYRIGHT NOTICE AND THIS PERMISSION NOTICE SHALL BE INCLUDED IN
22 karl 1.91 // ALL COPIES OR SUBSTANTIAL PORTIONS OF THE SOFTWARE. THE SOFTWARE IS PROVIDED
23 // "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT
24 // LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR
25 // PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
26 // HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
27 // ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
28 // WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
29 //
30 //==============================================================================
31 //
32 //%/////////////////////////////////////////////////////////////////////////////
33
34 #include "Config.h"
35 #include "Constants.h"
36 #include <iostream>
37
38 #include "Network.h"
39 #include "Socket.h"
40 #include "TLS.h"
41 #include "HTTPAcceptor.h"
42 #include "HTTPConnection.h"
|
43 dave.sudlik 1.93.4.2 #include "HostAddress.h"
|
44 karl 1.91 #include "Tracer.h"
|
45 kumpf 1.93 #include <Pegasus/Common/MessageLoader.h>
|
46 karl 1.91
47 #ifdef PEGASUS_PLATFORM_OS400_ISERIES_IBM
48 #include "EBCDIC_OS400.h"
49 #endif
50
51
52 PEGASUS_USING_STD;
53
54 PEGASUS_NAMESPACE_BEGIN
55
56
57 static int MAX_CONNECTION_QUEUE_LENGTH = -1;
58
59 ////////////////////////////////////////////////////////////////////////////////
60 //
61 // HTTPAcceptorRep
62 //
63 ////////////////////////////////////////////////////////////////////////////////
64
65 class HTTPAcceptorRep
66 {
67 karl 1.91 public:
|
68 dave.sudlik 1.93.4.2 HTTPAcceptorRep(Uint16 connectionType)
|
69 karl 1.91 {
|
70 dave.sudlik 1.93.4.2 if (connectionType == HTTPAcceptor::LOCAL_CONNECTION)
|
71 karl 1.91 {
72 #ifndef PEGASUS_DISABLE_LOCAL_DOMAIN_SOCKET
|
73 kumpf 1.92 address =
74 reinterpret_cast<struct sockaddr*>(new struct sockaddr_un);
|
75 karl 1.91 address_size = sizeof(struct sockaddr_un);
76 #else
77 PEGASUS_ASSERT(false);
78 #endif
79 }
|
80 dave.sudlik 1.93.4.2 #ifdef PEGASUS_ENABLE_IPV6
81 else if (connectionType == HTTPAcceptor::IPV6_CONNECTION)
82 {
83 address =
84 reinterpret_cast<struct sockaddr*>(new struct sockaddr_in6);
85 address_size = sizeof(struct sockaddr_in6);
86 }
87 #endif
88 else if (connectionType == HTTPAcceptor::IPV4_CONNECTION)
|
89 karl 1.91 {
|
90 kumpf 1.92 address =
91 reinterpret_cast<struct sockaddr*>(new struct sockaddr_in);
|
92 karl 1.91 address_size = sizeof(struct sockaddr_in);
93 }
|
94 dave.sudlik 1.93.4.2 else
95 {
96 PEGASUS_ASSERT(false);
|
97 karl 1.91 }
|
98 dave.sudlik 1.93.4.2 }
99
|
100 karl 1.91 ~HTTPAcceptorRep()
101 {
102 delete address;
103 }
104 struct sockaddr* address;
105
106 SocketLength address_size;
107 Mutex _connection_mut;
108
109 SocketHandle socket;
110 Array<HTTPConnection*> connections;
111 };
112
113
114 ////////////////////////////////////////////////////////////////////////////////
115 //
116 // HTTPAcceptor
117 //
118 ////////////////////////////////////////////////////////////////////////////////
119
120 HTTPAcceptor::HTTPAcceptor(Monitor* monitor,
121 karl 1.91 MessageQueue* outputMessageQueue,
|
122 dave.sudlik 1.93.4.2 Uint16 connectionType,
|
123 karl 1.91 Uint32 portNumber,
124 SSLContext * sslcontext,
125 ReadWriteSem* sslContextObjectLock)
126 : Base(PEGASUS_QUEUENAME_HTTPACCEPTOR), // ATTN: Need unique names?
127 _monitor(monitor),
128 _outputMessageQueue(outputMessageQueue),
129 _rep(0),
130 _entry_index(-1),
|
131 dave.sudlik 1.93.4.2 _connectionType(connectionType),
|
132 karl 1.91 _portNumber(portNumber),
133 _sslcontext(sslcontext),
|
134 dave.sudlik 1.93.4.3 _sslContextObjectLock(sslContextObjectLock),
135 _idleConnectionTimeoutSeconds(0)
|
136 karl 1.91 {
137 Socket::initializeInterface();
138
139 /*
|
140 kumpf 1.92 Platforms interpret the value of MAX_CONNECTION_QUEUE_LENGTH
141 differently. Some platforms interpret the value literally, while
142 others multiply a fudge factor. When the server is under stress from
143 multiple clients with multiple requests, toggling this number may
144 prevent clients from being dropped. Instead of hard coding the
145 value, we allow an environment variable to be set which specifies a
146 number greater than the maximum concurrent client connections
147 possible. If this environment var is not specified, then
148 MAX_CONNECTION_QUEUE_LENGTH = 15.
|
149 karl 1.91 */
150
|
151 kumpf 1.92 //To engage runtime backlog queue length: uncomment the following block AND
152 //comment out the line MAX_CONNECTION_QUEUE_LENGTH = 15
|
153 karl 1.91
154 /*
|
155 kumpf 1.92 if (MAX_CONNECTION_QUEUE_LENGTH == -1)
156 {
|
157 karl 1.91 #ifdef PEGASUS_PLATFORM_OS400_ISERIES_IBM
158 #pragma convert(37)
|
159 kumpf 1.92 const char* env = getenv("PEGASUS_MAX_BACKLOG_CONNECTION_QUEUE");
160 EtoA(env);
|
161 karl 1.91 #pragma convert(0)
162 #else
|
163 kumpf 1.92 const char* env = getenv("PEGASUS_MAX_BACKLOG_CONNECTION_QUEUE");
|
164 karl 1.91 #endif
|
165 kumpf 1.92 if (!env)
166 {
|
167 karl 1.91 MAX_CONNECTION_QUEUE_LENGTH = 15;
|
168 kumpf 1.92 }
169 else
170 {
171 char* end = NULL;
172 MAX_CONNECTION_QUEUE_LENGTH = strtol(env, &end, 10);
173 if (*end)
174 MAX_CONNECTION_QUEUE_LENGTH = 15;
175 cout << " MAX_CONNECTION_QUEUE_LENGTH = " <<
176 MAX_CONNECTION_QUEUE_LENGTH << endl;
177 }
|
178 karl 1.91 }
179 */
|
180 kumpf 1.92 MAX_CONNECTION_QUEUE_LENGTH = 15;
|
181 karl 1.91 }
182
183 HTTPAcceptor::~HTTPAcceptor()
184 {
|
185 kumpf 1.92 destroyConnections();
186 unbind();
187 // ATTN: Is this correct in a multi-HTTPAcceptor server?
188 Socket::uninitializeInterface();
|
189 karl 1.91 }
190
191 void HTTPAcceptor::handleEnqueue(Message *message)
192 {
|
193 kumpf 1.92 if (!message)
194 return;
195
196 PEGASUS_ASSERT(_rep != 0);
197 switch (message->getType())
198 {
199 case SOCKET_MESSAGE:
200 {
201 SocketMessage* socketMessage = (SocketMessage*)message;
202
203 // If this is a connection request:
204
205 if (socketMessage->socket == _rep->socket &&
206 socketMessage->events & SocketMessage::READ)
207 {
208 _acceptConnection();
209 }
210 else
211 {
212 // ATTN! this can't happen!
|
213 marek 1.93.4.1 PEG_TRACE_CSTRING(TRC_DISCARDED_DATA, Tracer::LEVEL2,
|
214 kumpf 1.92 "HTTPAcceptor::handleEnqueue: Invalid SOCKET_MESSAGE "
215 "received.");
216 }
|
217 karl 1.91
218 break;
|
219 kumpf 1.92 }
220
221 case CLOSE_CONNECTION_MESSAGE:
222 {
223 CloseConnectionMessage* closeConnectionMessage =
224 (CloseConnectionMessage*)message;
225
226 AutoMutex autoMut(_rep->_connection_mut);
227
228 for (Uint32 i = 0, n = _rep->connections.size(); i < n; i++)
229 {
230 HTTPConnection* connection = _rep->connections[i];
231 SocketHandle socket = connection->getSocket();
232
233 if (socket == closeConnectionMessage->socket)
234 {
235 _monitor->unsolicitSocketMessages(socket);
236 _rep->connections.remove(i);
237 delete connection;
238 break;
239 }
240 kumpf 1.92 }
|
241 karl 1.91
|
242 kumpf 1.92 break;
243 }
|
244 karl 1.91
|
245 kumpf 1.92 default:
246 // ATTN: need unexpected message error!
|
247 marek 1.93.4.1 PEG_TRACE_CSTRING(TRC_DISCARDED_DATA, Tracer::LEVEL2,
|
248 kumpf 1.92 "HTTPAcceptor::handleEnqueue: Invalid MESSAGE received.");
249 break;
250 }
|
251 karl 1.91
|
252 kumpf 1.92 delete message;
|
253 karl 1.91 }
254
255
256 void HTTPAcceptor::handleEnqueue()
257 {
|
258 kumpf 1.92 Message* message = dequeue();
|
259 karl 1.91
|
260 kumpf 1.92 if (!message)
261 {
|
262 marek 1.93.4.1 PEG_TRACE_CSTRING(TRC_DISCARDED_DATA, Tracer::LEVEL2,
|
263 kumpf 1.92 "HTTPAcceptor::handleEnqueue(): No message on queue.");
264 return;
265 }
|
266 karl 1.91
|
267 kumpf 1.92 handleEnqueue(message);
|
268 karl 1.91 }
269
270 void HTTPAcceptor::bind()
271 {
|
272 kumpf 1.92 if (_rep)
273 {
274 MessageLoaderParms parms("Common.HTTPAcceptor.ALREADY_BOUND",
275 "HTTPAcceptor already bound");
|
276 karl 1.91
|
277 marek 1.93.4.1 PEG_TRACE_CSTRING(TRC_DISCARDED_DATA, Tracer::LEVEL2,
|
278 kumpf 1.92 "HTTPAcceptor::bind: HTTPAcceptor already bound.");
279 throw BindFailedException(parms);
280 }
|
281 karl 1.91
|
282 dave.sudlik 1.93.4.2 _rep = new HTTPAcceptorRep(_connectionType);
|
283 karl 1.91
|
284 kumpf 1.92 // bind address
285 _bind();
|
286 karl 1.91 }
287
288 /**
|
289 kumpf 1.92 _bind - creates a new server socket and bind socket to the port address.
290 If PEGASUS_DISABLE_LOCAL_DOMAIN_SOCKET is not defined, the port number is
291 ignored and a domain socket is bound.
|
292 karl 1.91 */
293 void HTTPAcceptor::_bind()
294 {
|
295 kumpf 1.92 PEGASUS_ASSERT(_rep != 0);
296 // Create address:
|
297 dave.sudlik 1.93.4.2 memset(_rep->address, 0, _rep->address_size);
|
298 karl 1.91
|
299 dave.sudlik 1.93.4.2 if (_connectionType == LOCAL_CONNECTION)
|
300 kumpf 1.92 {
|
301 karl 1.91 #ifndef PEGASUS_DISABLE_LOCAL_DOMAIN_SOCKET
|
302 kumpf 1.92 reinterpret_cast<struct sockaddr_un*>(_rep->address)->sun_family =
303 AF_UNIX;
304 strcpy(reinterpret_cast<struct sockaddr_un*>(_rep->address)->sun_path,
305 PEGASUS_LOCAL_DOMAIN_SOCKET_PATH);
|
306 karl 1.91 #ifdef PEGASUS_PLATFORM_OS400_ISERIES_IBM
|
307 kumpf 1.92 AtoE(reinterpret_cast<struct sockaddr_un*>(_rep->address)->sun_path);
|
308 karl 1.91 #endif
|
309 kumpf 1.92 ::unlink(
310 reinterpret_cast<struct sockaddr_un*>(_rep->address)->sun_path);
|
311 karl 1.91 #else
|
312 kumpf 1.92 PEGASUS_ASSERT(false);
|
313 karl 1.91 #endif
|
314 kumpf 1.92 }
|
315 dave.sudlik 1.93.4.2 #ifdef PEGASUS_ENABLE_IPV6
316 else if (_connectionType == IPV6_CONNECTION)
317 {
318 reinterpret_cast<struct sockaddr_in6*>(_rep->address)->sin6_addr =
319 in6addr_any;
320 reinterpret_cast<struct sockaddr_in6*>(_rep->address)->sin6_family =
321 AF_INET6;
322 reinterpret_cast<struct sockaddr_in6*>(_rep->address)->sin6_port =
323 htons(_portNumber);
324 }
325 #endif
326 else if(_connectionType == IPV4_CONNECTION)
|
327 kumpf 1.92 {
328 reinterpret_cast<struct sockaddr_in*>(_rep->address)->sin_addr.s_addr =
329 INADDR_ANY;
330 reinterpret_cast<struct sockaddr_in*>(_rep->address)->sin_family =
331 AF_INET;
332 reinterpret_cast<struct sockaddr_in*>(_rep->address)->sin_port =
333 htons(_portNumber);
334 }
|
335 dave.sudlik 1.93.4.2 else
336 {
337 PEGASUS_ASSERT(false);
338 }
|
339 kumpf 1.92
340 // Create socket:
341
|
342 dave.sudlik 1.93.4.2 if (_connectionType == LOCAL_CONNECTION)
|
343 kumpf 1.92 {
344 _rep->socket = Socket::createSocket(AF_UNIX, SOCK_STREAM, 0);
345 }
|
346 dave.sudlik 1.93.4.2 #ifdef PEGASUS_ENABLE_IPV6
347 else if (_connectionType == IPV6_CONNECTION)
348 {
349 _rep->socket = Socket::createSocket(PF_INET6, SOCK_STREAM, IPPROTO_TCP);
350 }
351 #endif
352 else if (_connectionType == IPV4_CONNECTION)
|
353 kumpf 1.92 {
354 _rep->socket = Socket::createSocket(PF_INET, SOCK_STREAM, IPPROTO_TCP);
355 }
|
356 dave.sudlik 1.93.4.2 else
357 {
358 PEGASUS_ASSERT(false);
359 }
|
360 kumpf 1.92
361 if (_rep->socket < 0)
362 {
363 delete _rep;
364 _rep = 0;
365 MessageLoaderParms parms("Common.HTTPAcceptor.FAILED_CREATE_SOCKET",
366 "Failed to create socket");
|
367 marek 1.93.4.1 PEG_TRACE_CSTRING(TRC_DISCARDED_DATA, Tracer::LEVEL2,
|
368 kumpf 1.92 "HTTPAcceptor::_bind _rep->socket < 0");
369 throw BindFailedException(parms);
370 }
|
371 karl 1.91
|
372 kumpf 1.93.4.4 Socket::disableBlocking(_rep->socket);
|
373 karl 1.91
374 // set the close-on-exec bit for this file handle.
375 // any unix that forks needs this bit set.
376 #if !defined PEGASUS_OS_TYPE_WINDOWS && !defined(PEGASUS_OS_VMS)
|
377 kumpf 1.92 int sock_flags;
378 if ((sock_flags = fcntl(_rep->socket, F_GETFD, 0)) < 0)
379 {
|
380 marek 1.93.4.1 PEG_TRACE_CSTRING(TRC_DISCARDED_DATA, Tracer::LEVEL2,
|
381 kumpf 1.92 "HTTPAcceptor::_bind: fcntl(F_GETFD) failed");
382 }
383 else
384 {
385 sock_flags |= FD_CLOEXEC;
386 if (fcntl(_rep->socket, F_SETFD, sock_flags) < 0)
387 {
|
388 marek 1.93.4.1 PEG_TRACE_CSTRING(TRC_DISCARDED_DATA, Tracer::LEVEL2,
|
389 kumpf 1.92 "HTTPAcceptor::_bind: fcntl(F_SETFD) failed");
390 }
391 }
392 #endif
393
394
395 //
396 // Set the socket option SO_REUSEADDR to reuse the socket address so
397 // that we can rebind to a new socket using the same address when we
398 // need to resume the cimom as a result of a timeout during a Shutdown
399 // operation.
400 //
401 int opt=1;
402 if (setsockopt(_rep->socket, SOL_SOCKET, SO_REUSEADDR,
403 (char *)&opt, sizeof(opt)) < 0)
404 {
405 Socket::close(_rep->socket);
406 delete _rep;
407 _rep = 0;
408 MessageLoaderParms parms("Common.HTTPAcceptor.FAILED_SET_SOCKET_OPTION",
409 "Failed to set socket option");
|
410 marek 1.93.4.1 PEG_TRACE_CSTRING(TRC_DISCARDED_DATA, Tracer::LEVEL2,
|
411 kumpf 1.92 "HTTPAcceptor::_bind: Failed to set socket option.");
412 throw BindFailedException(parms);
413 }
414
415
416 //
417 // Bind socket to port:
418 //
419 if (::bind(_rep->socket, _rep->address, _rep->address_size) < 0)
420 {
421 Socket::close(_rep->socket);
422 delete _rep;
423 _rep = 0;
424 MessageLoaderParms parms("Common.HTTPAcceptor.FAILED_BIND_SOCKET",
425 "Failed to bind socket");
|
426 marek 1.93.4.1 PEG_TRACE_CSTRING(TRC_DISCARDED_DATA, Tracer::LEVEL2,
|
427 kumpf 1.92 "HTTPAcceptor::_bind: Failed to bind socket.");
428 throw BindFailedException(parms);
429 }
430
431
432 //
433 // Get the actual port value used if the caller specified a port value of 0.
434 //
435 if (_portNumber == 0)
436 {
437 sockaddr_in buf;
438 SocketLength bufSize = sizeof(buf);
439 if (getsockname(_rep->socket, reinterpret_cast<sockaddr *>(&buf),
440 &bufSize) == 0 )
441 {
442 _portNumber = ntohs(buf.sin_port);
443 }
444 }
445
446
447 //
448 kumpf 1.92 // Change permissions on Linux local domain socket to allow writes by
449 // others.
450 //
|
451 karl 1.91 #if !defined(PEGASUS_DISABLE_LOCAL_DOMAIN_SOCKET) && \
|
452 kumpf 1.92 (defined(PEGASUS_PLATFORM_LINUX_GENERIC_GNU) || \
453 defined(PEGASUS_PLATFORM_ZOS_ZSERIES_IBM))
|
454 dave.sudlik 1.93.4.2 if (_connectionType == LOCAL_CONNECTION)
|
455 kumpf 1.92 {
456 if (::chmod(PEGASUS_LOCAL_DOMAIN_SOCKET_PATH,
457 S_IRUSR | S_IWUSR | S_IXUSR |
458 S_IRGRP | S_IWGRP | S_IXGRP |
459 S_IROTH | S_IWOTH | S_IXOTH ) < 0 )
460 {
461 Socket::close(_rep->socket);
462 delete _rep;
463 _rep = 0;
464 MessageLoaderParms parms("Common.HTTPAcceptor.FAILED_BIND_SOCKET",
465 "Failed to bind socket");
|
466 marek 1.93.4.1 PEG_TRACE_CSTRING(TRC_DISCARDED_DATA, Tracer::LEVEL2,
|
467 kumpf 1.92 "HTTPAcceptor::_bind: Failed to set domain socket "
468 "permissions.");
469 throw BindFailedException(parms);
470 }
471 }
472 #endif
473
474 // Set up listening on the given socket:
475
476 //int const MAX_CONNECTION_QUEUE_LENGTH = 15;
477
478 if (listen(_rep->socket, MAX_CONNECTION_QUEUE_LENGTH) < 0)
479 {
480 Socket::close(_rep->socket);
481 delete _rep;
482 _rep = 0;
483 MessageLoaderParms parms("Common.HTTPAcceptor.FAILED_BIND_SOCKET",
484 "Failed to bind socket");
|
485 marek 1.93.4.1 PEG_TRACE_CSTRING(TRC_DISCARDED_DATA, Tracer::LEVEL2,
|
486 kumpf 1.92 "HTTPAcceptor::_bind: Failed to bind socket(1).");
487 throw BindFailedException(parms);
488 }
489
490 // Register to receive SocketMessages on this socket:
491
492 if (-1 == ( _entry_index = _monitor->solicitSocketMessages(
493 _rep->socket,
494 SocketMessage::READ | SocketMessage::EXCEPTION,
495 getQueueId(),
496 Monitor::ACCEPTOR)))
497 {
498 Socket::close(_rep->socket);
499 delete _rep;
500 _rep = 0;
501 MessageLoaderParms parms(
502 "Common.HTTPAcceptor.FAILED_SOLICIT_SOCKET_MESSAGES",
503 "Failed to solicit socket messaeges");
|
504 marek 1.93.4.1 PEG_TRACE_CSTRING(TRC_DISCARDED_DATA, Tracer::LEVEL2,
|
505 kumpf 1.92 "HTTPAcceptor::_bind: Failed to solicit socket messages(2).");
506 throw BindFailedException(parms);
507 }
|
508 karl 1.91 }
509
510 /**
|
511 kumpf 1.92 closeConnectionSocket - close the server listening socket to disallow
512 new client connections.
|
513 karl 1.91 */
514 void HTTPAcceptor::closeConnectionSocket()
515 {
|
516 kumpf 1.92 if (_rep)
517 {
518 // unregister the socket
519
520 // ATTN - comment out - see CIMServer::stopClientConnection()
521 //_monitor->unsolicitSocketMessages(_rep->socket);
522
523 // close the socket
524 Socket::close(_rep->socket);
525 // Unlink Local Domain Socket Bug# 3312
|
526 dave.sudlik 1.93.4.2 if (_connectionType == LOCAL_CONNECTION)
|
527 kumpf 1.92 {
|
528 karl 1.91 #ifndef PEGASUS_DISABLE_LOCAL_DOMAIN_SOCKET
|
529 marek 1.93.4.1 PEG_TRACE_CSTRING(TRC_HTTP, Tracer::LEVEL2,
|
530 kumpf 1.92 "HTTPAcceptor::closeConnectionSocket Unlinking local "
531 "connection.");
532 ::unlink(
533 reinterpret_cast<struct sockaddr_un*>(_rep->address)->sun_path);
|
534 karl 1.91 #else
|
535 kumpf 1.92 PEGASUS_ASSERT(false);
|
536 karl 1.91 #endif
|
537 kumpf 1.92 }
538 }
539 else
540 {
|
541 marek 1.93.4.1 PEG_TRACE_CSTRING(TRC_DISCARDED_DATA, Tracer::LEVEL2,
|
542 kumpf 1.92 "HTTPAcceptor::closeConnectionSocket failure _rep is null.");
543 }
|
544 karl 1.91 }
545
546 /**
547 reopenConnectionSocket - creates a new server socket.
548 */
549 void HTTPAcceptor::reopenConnectionSocket()
550 {
|
551 kumpf 1.92 if (_rep)
552 {
553 _bind();
554 }
555 else
556 {
|
557 marek 1.93.4.1 PEG_TRACE_CSTRING(TRC_DISCARDED_DATA, Tracer::LEVEL2,
|
558 kumpf 1.92 "HTTPAcceptor::reopenConnectionSocket failure _rep is null.");
559 }
|
560 karl 1.91 }
561
562
563 /**
564 reconnectConnectionSocket - creates a new server socket.
565 */
566 void HTTPAcceptor::reconnectConnectionSocket()
567 {
|
568 kumpf 1.92 if (_rep)
569 {
570 // unregister the socket
571 _monitor->unsolicitSocketMessages(_rep->socket);
572 // close the socket
573 Socket::close(_rep->socket);
574 // Unlink Local Domain Socket Bug# 3312
|
575 dave.sudlik 1.93.4.2 if (_connectionType == LOCAL_CONNECTION)
|
576 kumpf 1.92 {
|
577 karl 1.91 #ifndef PEGASUS_DISABLE_LOCAL_DOMAIN_SOCKET
|
578 marek 1.93.4.1 PEG_TRACE_CSTRING(TRC_HTTP, Tracer::LEVEL2,
|
579 kumpf 1.92 "HTTPAcceptor::reconnectConnectionSocket Unlinking local "
580 "connection." );
581 ::unlink(
582 reinterpret_cast<struct sockaddr_un*>(_rep->address)->sun_path);
|
583 karl 1.91 #else
|
584 kumpf 1.92 PEGASUS_ASSERT(false);
|
585 karl 1.91 #endif
|
586 kumpf 1.92 }
587 // open the socket
588 _bind();
589 }
590 else
591 {
|
592 marek 1.93.4.1 PEG_TRACE_CSTRING(TRC_DISCARDED_DATA, Tracer::LEVEL2,
|
593 kumpf 1.92 "HTTPAcceptor::reconnectConnectionSocket failure _rep is null.");
594 }
|
595 karl 1.91 }
596
597 /**
|
598 kumpf 1.92 getOutstandingRequestCount - returns the number of outstanding requests.
|
599 karl 1.91 */
600 Uint32 HTTPAcceptor::getOutstandingRequestCount() const
601 {
|
602 kumpf 1.92 Uint32 count = 0;
603 if (_rep)
604 {
605 AutoMutex autoMut(_rep->_connection_mut);
606 if (_rep->connections.size() > 0)
607 {
608 HTTPConnection* connection = _rep->connections[0];
609 count = connection->getRequestCount();
610 }
611 }
612 return count;
|
613 karl 1.91 }
614
615
616 /**
617 getPortNumber - returns the port number used for the connection
618 */
619 Uint32 HTTPAcceptor::getPortNumber() const
620 {
621 return _portNumber;
622 }
623
624 void HTTPAcceptor::setSocketWriteTimeout(Uint32 socketWriteTimeout)
625 {
626 _socketWriteTimeout = socketWriteTimeout;
627 }
628
|
629 dave.sudlik 1.93.4.3 void HTTPAcceptor::setIdleConnectionTimeout(Uint32 idleConnectionTimeoutSeconds)
630 {
631 _idleConnectionTimeoutSeconds = idleConnectionTimeoutSeconds;
632 }
633
|
634 karl 1.91 void HTTPAcceptor::unbind()
635 {
|
636 kumpf 1.92 if (_rep)
637 {
638 _portNumber = 0;
639 Socket::close(_rep->socket);
|
640 karl 1.91
|
641 dave.sudlik 1.93.4.2 if (_connectionType == LOCAL_CONNECTION)
|
642 kumpf 1.92 {
|
643 karl 1.91 #ifndef PEGASUS_DISABLE_LOCAL_DOMAIN_SOCKET
|
644 kumpf 1.92 ::unlink(
645 reinterpret_cast<struct sockaddr_un*>(_rep->address)->sun_path);
|
646 karl 1.91 #else
|
647 kumpf 1.92 PEGASUS_ASSERT(false);
|
648 karl 1.91 #endif
|
649 kumpf 1.92 }
|
650 karl 1.91
|
651 kumpf 1.92 delete _rep;
652 _rep = 0;
653 }
654 else
655 {
|
656 marek 1.93.4.1 PEG_TRACE_CSTRING(TRC_DISCARDED_DATA, Tracer::LEVEL2,
|
657 kumpf 1.92 "HTTPAcceptor::unbind failure _rep is null." );
658 }
|
659 karl 1.91 }
660
661 void HTTPAcceptor::destroyConnections()
662 {
|
663 kumpf 1.92 if (_rep)
664 {
665 // For each connection created by this object:
|
666 karl 1.91
|
667 kumpf 1.92 AutoMutex autoMut(_rep->_connection_mut);
668 for (Uint32 i = 0, n = _rep->connections.size(); i < n; i++)
669 {
670 HTTPConnection* connection = _rep->connections[i];
671 SocketHandle socket = connection->getSocket();
|
672 karl 1.91
|
673 kumpf 1.92 // Unsolicit SocketMessages:
|
674 karl 1.91
|
675 kumpf 1.92 _monitor->unsolicitSocketMessages(socket);
|
676 karl 1.91
|
677 kumpf 1.92 // Destroy the connection (causing it to close):
|
678 karl 1.91
|
679 kumpf 1.92 while (connection->refcount.get()) { }
680 delete connection;
681 }
|
682 karl 1.91
|
683 kumpf 1.92 _rep->connections.clear();
684 }
|
685 karl 1.91 }
686
687 void HTTPAcceptor::_acceptConnection()
688 {
|
689 kumpf 1.92 // This function cannot be called on an invalid socket!
|
690 karl 1.91
|
691 kumpf 1.92 PEGASUS_ASSERT(_rep != 0);
|
692 karl 1.91
|
693 kumpf 1.92 // Accept the connection (populate the address):
|
694 karl 1.91
|
695 kumpf 1.92 struct sockaddr* accept_address;
696 SocketLength address_size;
|
697 karl 1.91
|
698 dave.sudlik 1.93.4.2 if (_connectionType == LOCAL_CONNECTION)
|
699 kumpf 1.92 {
|
700 karl 1.91 #ifndef PEGASUS_DISABLE_LOCAL_DOMAIN_SOCKET
|
701 kumpf 1.92 accept_address =
702 reinterpret_cast<struct sockaddr*>(new struct sockaddr_un);
703 address_size = sizeof(struct sockaddr_un);
|
704 karl 1.91 #else
|
705 kumpf 1.92 PEGASUS_ASSERT(false);
|
706 karl 1.91 #endif
|
707 kumpf 1.92 }
708 else
709 {
|
710 dave.sudlik 1.93.4.2 #ifdef PEGASUS_ENABLE_IPV6
711 accept_address =
712 reinterpret_cast<struct sockaddr*>
713 (new struct sockaddr_storage);
714 address_size = sizeof(struct sockaddr_storage);
715 #else
|
716 kumpf 1.92 accept_address =
717 reinterpret_cast<struct sockaddr*>(new struct sockaddr_in);
718 address_size = sizeof(struct sockaddr_in);
|
719 dave.sudlik 1.93.4.2 #endif
|
720 kumpf 1.92 }
721
|
722 kumpf 1.93.4.4 // It is not necessary to handle EINTR errors from this accept() call.
723 // An EINTR error should not occur on a non-blocking socket. If the
724 // listen socket is blocking and EINTR occurs, the new socket connection
725 // is not accepted here.
726
727 // EAGAIN errors are also not handled here. An EAGAIN error should not
728 // occur after select() indicates that the listen socket is available for
729 // reading. If the accept() fails with an EAGAIN error code, a new
730 // connection is not accepted here.
731
|
732 kumpf 1.92 SocketHandle socket = accept(_rep->socket, accept_address, &address_size);
733
734 if (socket == PEGASUS_SOCKET_ERROR)
735 {
736 // the remote connection is invalid, destroy client address.
737 delete accept_address;
738
739 // TCPIP is down reconnect this acceptor
740 if (getSocketError() == PEGASUS_NETWORK_TCPIP_STOPPED)
741 {
|
742 marek 1.93.4.1 PEG_TRACE_CSTRING(TRC_DISCARDED_DATA, Tracer::LEVEL2,
|
743 kumpf 1.92 "Socket has an IO error. TCP/IP down. Try to reconnect.");
744
745 reconnectConnectionSocket();
746
747 return;
748 }
|
749 karl 1.91
|
750 kumpf 1.92 Logger::put(Logger::STANDARD_LOG, System::CIMSERVER, Logger::TRACE,
751 "HTTPAcceptor - accept() failure. errno: $0", errno);
|
752 karl 1.91
|
753 marek 1.93.4.1 PEG_TRACE_CSTRING(TRC_DISCARDED_DATA, Tracer::LEVEL2,
|
754 kumpf 1.92 "HTTPAcceptor: accept() failed");
755 return;
756 }
|
757 marek 1.93.4.6 #ifndef(PEGASUS_OS_TYPE_WINDOWS)
|
758 marek 1.93.4.5 // We need to ensure that the socket number is not higher than
759 // what fits into FD_SETSIZE, because we else won't be able to select on it
760 // and won't ever communicate correct on that socket.
761 if (socket >= FD_SETSIZE)
762 {
763 // the remote connection is invalid, destroy client address.
764 delete accept_address;
765
766 Logger::put(Logger::STANDARD_LOG, System::CIMSERVER, Logger::TRACE,
767 "HTTPAcceptor out of available sockets. "
768 "Closing connection to the new client.");
769
770 PEG_TRACE(
771 (TRC_DISCARDED_DATA,
772 Tracer::LEVEL2,
773 "accept() returned too large socket number %d.",
774 socket));
775
776 // close the connection
777 Socket::close(socket);
778 return;
779 marek 1.93.4.5 }
|
780 marek 1.93.4.6 #endif
|
781 karl 1.91
|
782 kumpf 1.92 String ipAddress;
|
783 karl 1.91
|
784 dave.sudlik 1.93.4.2 if (_connectionType == LOCAL_CONNECTION)
|
785 kumpf 1.92 {
786 ipAddress = "localhost";
787 }
788 else
789 {
|
790 dave.sudlik 1.93.4.2 #ifdef PEGASUS_ENABLE_IPV6
791 char ipBuffer[PEGASUS_INET6_ADDRSTR_LEN];
792 int rc;
793 while ((rc = getnameinfo(accept_address, address_size, ipBuffer,
794 PEGASUS_INET6_ADDRSTR_LEN, 0, 0, NI_NUMERICHOST)) == EAI_AGAIN)
795 ;
796 if (rc)
797 {
798 Logger::put(Logger::STANDARD_LOG, System::CIMSERVER, Logger::TRACE,
799 "HTTPAcceptor - getnameinfo() failure. rc: $0", rc);
800
801 PEG_TRACE_CSTRING(TRC_DISCARDED_DATA, Tracer::LEVEL2,
802 "HTTPAcceptor: getnameinfo() failed");
803 delete accept_address;
804 Socket::close(socket);
805 return;
806 }
807 ipAddress = ipBuffer;
808 #else
|
809 kumpf 1.92 unsigned char* sa = reinterpret_cast<unsigned char*>(
810 &reinterpret_cast<struct sockaddr_in*>(
811 accept_address)->sin_addr.s_addr);
812 char ipBuffer[32];
813 sprintf(ipBuffer, "%u.%u.%u.%u", sa[0], sa[1], sa[2], sa[3]);
814 ipAddress = ipBuffer;
|
815 dave.sudlik 1.93.4.2 #endif
|
816 kumpf 1.92 }
|
817 karl 1.91
|
818 kumpf 1.92 delete accept_address;
|
819 karl 1.91
820 // set the close on exec flag
821 #if !defined(PEGASUS_OS_TYPE_WINDOWS) && !defined(PEGASUS_OS_VMS)
|
822 kumpf 1.92 int sock_flags;
823 if ((sock_flags = fcntl(socket, F_GETFD, 0)) < 0)
824 {
|
825 marek 1.93.4.1 PEG_TRACE_CSTRING(TRC_DISCARDED_DATA, Tracer::LEVEL2,
|
826 kumpf 1.92 "HTTPAcceptor: fcntl(F_GETFD) failed");
827 }
828 else
829 {
830 sock_flags |= FD_CLOEXEC;
831 if (fcntl(socket, F_SETFD, sock_flags) < 0)
832 {
|
833 marek 1.93.4.1 PEG_TRACE_CSTRING(TRC_DISCARDED_DATA, Tracer::LEVEL2,
|
834 kumpf 1.92 "HTTPAcceptor: fcntl(F_SETFD) failed");
835 }
836 }
|
837 karl 1.91 #endif
838
839
|
840 kumpf 1.92 PEG_LOGGER_TRACE((Logger::STANDARD_LOG, System::CIMSERVER, 0,
841 "HTTPAcceptor - accept() success. Socket: $1" ,socket));
842
843 AutoPtr<MP_Socket> mp_socket(new MP_Socket(
844 socket, _sslcontext, _sslContextObjectLock));
845
|
846 kumpf 1.93.4.4 mp_socket->disableBlocking();
|
847 kumpf 1.92 mp_socket->setSocketWriteTimeout(_socketWriteTimeout);
848
|
849 kumpf 1.93.4.4 // Perform the SSL handshake, if applicable.
|
850 kumpf 1.92
851 Sint32 socketAcceptStatus = mp_socket->accept();
852
853 if (socketAcceptStatus < 0)
854 {
|
855 marek 1.93.4.1 PEG_TRACE_CSTRING(TRC_DISCARDED_DATA, Tracer::LEVEL2,
|
856 kumpf 1.92 "HTTPAcceptor: SSL_accept() failed");
857 mp_socket->close();
858 return;
859 }
860
861 // Create a new connection and add it to the connection list:
862
863 HTTPConnection* connection = new HTTPConnection(_monitor, mp_socket,
864 ipAddress, this, static_cast<MessageQueue *>(_outputMessageQueue));
865
|
866 dave.sudlik 1.93.4.3 if (_idleConnectionTimeoutSeconds)
867 {
868 connection->_idleConnectionTimeoutSeconds =
869 _idleConnectionTimeoutSeconds;
870 Time::gettimeofday(&connection->_idleStartTime);
871 }
872
|
873 kumpf 1.92 if (socketAcceptStatus == 0)
874 {
|
875 marek 1.93.4.1 PEG_TRACE_CSTRING(TRC_HTTP, Tracer::LEVEL2,
|
876 kumpf 1.92 "HTTPAcceptor: SSL_accept() pending");
877 connection->_acceptPending = true;
|
878 dave.sudlik 1.93.4.3 Time::gettimeofday(&connection->_acceptPendingStartTime);
|
879 kumpf 1.92 }
|
880 karl 1.91
|
881 kumpf 1.92 // Solicit events on this new connection's socket:
882 int index;
|
883 karl 1.91
|
884 kumpf 1.92 if (-1 == (index = _monitor->solicitSocketMessages(
885 connection->getSocket(),
886 SocketMessage::READ | SocketMessage::EXCEPTION,
887 connection->getQueueId(), Monitor::CONNECTION)) )
888 {
889 // ATTN-DE-P2-2003100503::TODO::Need to enhance code to return
890 // an error message to Client application.
|
891 marek 1.93.4.1 PEG_TRACE_CSTRING(TRC_DISCARDED_DATA, Tracer::LEVEL2,
|
892 kumpf 1.92 "HTTPAcceptor::_acceptConnection: Attempt to allocate entry in "
893 "_entries table failed.");
894 delete connection;
895 Socket::close(socket);
896 return;
897 }
|
898 karl 1.91
|
899 kumpf 1.92 // Save the socket for cleanup later:
900 connection->_entry_index = index;
901 AutoMutex autoMut(_rep->_connection_mut);
902 _rep->connections.append(connection);
|
903 karl 1.91 }
904
|
905 kumpf 1.92 PEGASUS_NAMESPACE_END
|