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 karl 1.91 #include "Tracer.h"
44 #include <Pegasus/Common/MessageLoader.h> //l10n
45
46 #ifdef PEGASUS_PLATFORM_OS400_ISERIES_IBM
47 #include "EBCDIC_OS400.h"
48 #endif
49
50
51 PEGASUS_USING_STD;
52
53 PEGASUS_NAMESPACE_BEGIN
54
55
56 static int MAX_CONNECTION_QUEUE_LENGTH = -1;
57
58 ////////////////////////////////////////////////////////////////////////////////
59 //
60 // HTTPAcceptorRep
61 //
62 ////////////////////////////////////////////////////////////////////////////////
63
64 karl 1.91 class HTTPAcceptorRep
65 {
66 public:
67 HTTPAcceptorRep(Boolean local)
68 {
69 if (local)
70 {
71 #ifndef PEGASUS_DISABLE_LOCAL_DOMAIN_SOCKET
|
72 kumpf 1.92 address =
73 reinterpret_cast<struct sockaddr*>(new struct sockaddr_un);
|
74 karl 1.91 address_size = sizeof(struct sockaddr_un);
75 #else
76 PEGASUS_ASSERT(false);
77 #endif
78 }
79 else
80 {
|
81 kumpf 1.92 address =
82 reinterpret_cast<struct sockaddr*>(new struct sockaddr_in);
|
83 karl 1.91 address_size = sizeof(struct sockaddr_in);
84 }
85 }
86 ~HTTPAcceptorRep()
87 {
88 delete address;
89 }
90 struct sockaddr* address;
91
92 SocketLength address_size;
93 Mutex _connection_mut;
94
95 SocketHandle socket;
96 Array<HTTPConnection*> connections;
97 };
98
99
100 ////////////////////////////////////////////////////////////////////////////////
101 //
102 // HTTPAcceptor
103 //
104 karl 1.91 ////////////////////////////////////////////////////////////////////////////////
105
106 HTTPAcceptor::HTTPAcceptor(Monitor* monitor,
107 MessageQueue* outputMessageQueue,
108 Boolean localConnection,
109 Uint32 portNumber,
110 SSLContext * sslcontext,
111 ReadWriteSem* sslContextObjectLock)
112 : Base(PEGASUS_QUEUENAME_HTTPACCEPTOR), // ATTN: Need unique names?
113 _monitor(monitor),
114 _outputMessageQueue(outputMessageQueue),
115 _rep(0),
116 _entry_index(-1),
117 _localConnection(localConnection),
118 _portNumber(portNumber),
119 _sslcontext(sslcontext),
120 _sslContextObjectLock(sslContextObjectLock)
121 {
122 Socket::initializeInterface();
123
124 /*
|
125 kumpf 1.92 Platforms interpret the value of MAX_CONNECTION_QUEUE_LENGTH
126 differently. Some platforms interpret the value literally, while
127 others multiply a fudge factor. When the server is under stress from
128 multiple clients with multiple requests, toggling this number may
129 prevent clients from being dropped. Instead of hard coding the
130 value, we allow an environment variable to be set which specifies a
131 number greater than the maximum concurrent client connections
132 possible. If this environment var is not specified, then
133 MAX_CONNECTION_QUEUE_LENGTH = 15.
|
134 karl 1.91 */
135
|
136 kumpf 1.92 //To engage runtime backlog queue length: uncomment the following block AND
137 //comment out the line MAX_CONNECTION_QUEUE_LENGTH = 15
|
138 karl 1.91
139 /*
|
140 kumpf 1.92 if (MAX_CONNECTION_QUEUE_LENGTH == -1)
141 {
|
142 karl 1.91 #ifdef PEGASUS_PLATFORM_OS400_ISERIES_IBM
143 #pragma convert(37)
|
144 kumpf 1.92 const char* env = getenv("PEGASUS_MAX_BACKLOG_CONNECTION_QUEUE");
145 EtoA(env);
|
146 karl 1.91 #pragma convert(0)
147 #else
|
148 kumpf 1.92 const char* env = getenv("PEGASUS_MAX_BACKLOG_CONNECTION_QUEUE");
|
149 karl 1.91 #endif
|
150 kumpf 1.92 if (!env)
151 {
|
152 karl 1.91 MAX_CONNECTION_QUEUE_LENGTH = 15;
|
153 kumpf 1.92 }
154 else
155 {
156 char* end = NULL;
157 MAX_CONNECTION_QUEUE_LENGTH = strtol(env, &end, 10);
158 if (*end)
159 MAX_CONNECTION_QUEUE_LENGTH = 15;
160 cout << " MAX_CONNECTION_QUEUE_LENGTH = " <<
161 MAX_CONNECTION_QUEUE_LENGTH << endl;
162 }
|
163 karl 1.91 }
164 */
|
165 kumpf 1.92 MAX_CONNECTION_QUEUE_LENGTH = 15;
|
166 karl 1.91 }
167
168 HTTPAcceptor::~HTTPAcceptor()
169 {
|
170 kumpf 1.92 destroyConnections();
171 unbind();
172 // ATTN: Is this correct in a multi-HTTPAcceptor server?
173 Socket::uninitializeInterface();
|
174 karl 1.91 }
175
176 void HTTPAcceptor::handleEnqueue(Message *message)
177 {
|
178 kumpf 1.92 if (!message)
179 return;
180
181 PEGASUS_ASSERT(_rep != 0);
182 switch (message->getType())
183 {
184 case SOCKET_MESSAGE:
185 {
186 SocketMessage* socketMessage = (SocketMessage*)message;
187
188 // If this is a connection request:
189
190 if (socketMessage->socket == _rep->socket &&
191 socketMessage->events & SocketMessage::READ)
192 {
193 _acceptConnection();
194 }
195 else
196 {
197 // ATTN! this can't happen!
198 Tracer::trace(TRC_DISCARDED_DATA, Tracer::LEVEL2,
199 kumpf 1.92 "HTTPAcceptor::handleEnqueue: Invalid SOCKET_MESSAGE "
200 "received.");
201 }
|
202 karl 1.91
203 break;
|
204 kumpf 1.92 }
205
206 case CLOSE_CONNECTION_MESSAGE:
207 {
208 CloseConnectionMessage* closeConnectionMessage =
209 (CloseConnectionMessage*)message;
210
211 AutoMutex autoMut(_rep->_connection_mut);
212
213 for (Uint32 i = 0, n = _rep->connections.size(); i < n; i++)
214 {
215 HTTPConnection* connection = _rep->connections[i];
216 SocketHandle socket = connection->getSocket();
217
218 if (socket == closeConnectionMessage->socket)
219 {
220 _monitor->unsolicitSocketMessages(socket);
221 _rep->connections.remove(i);
222 delete connection;
223 break;
224 }
225 kumpf 1.92 }
|
226 karl 1.91
|
227 kumpf 1.92 break;
228 }
|
229 karl 1.91
|
230 kumpf 1.92 default:
231 // ATTN: need unexpected message error!
232 Tracer::trace(TRC_DISCARDED_DATA, Tracer::LEVEL2,
233 "HTTPAcceptor::handleEnqueue: Invalid MESSAGE received.");
234 break;
235 }
|
236 karl 1.91
|
237 kumpf 1.92 delete message;
|
238 karl 1.91 }
239
240
241 void HTTPAcceptor::handleEnqueue()
242 {
|
243 kumpf 1.92 Message* message = dequeue();
|
244 karl 1.91
|
245 kumpf 1.92 if (!message)
246 {
247 Tracer::trace(TRC_DISCARDED_DATA, Tracer::LEVEL2,
248 "HTTPAcceptor::handleEnqueue(): No message on queue.");
249 return;
250 }
|
251 karl 1.91
|
252 kumpf 1.92 handleEnqueue(message);
|
253 karl 1.91 }
254
255 void HTTPAcceptor::bind()
256 {
|
257 kumpf 1.92 if (_rep)
258 {
259 MessageLoaderParms parms("Common.HTTPAcceptor.ALREADY_BOUND",
260 "HTTPAcceptor already bound");
|
261 karl 1.91
|
262 kumpf 1.92 Tracer::trace(TRC_DISCARDED_DATA, Tracer::LEVEL2,
263 "HTTPAcceptor::bind: HTTPAcceptor already bound.");
264 throw BindFailedException(parms);
265 }
|
266 karl 1.91
|
267 kumpf 1.92 _rep = new HTTPAcceptorRep(_localConnection);
|
268 karl 1.91
|
269 kumpf 1.92 // bind address
270 _bind();
|
271 karl 1.91 }
272
273 /**
|
274 kumpf 1.92 _bind - creates a new server socket and bind socket to the port address.
275 If PEGASUS_DISABLE_LOCAL_DOMAIN_SOCKET is not defined, the port number is
276 ignored and a domain socket is bound.
|
277 karl 1.91 */
278 void HTTPAcceptor::_bind()
279 {
|
280 kumpf 1.92 PEGASUS_ASSERT(_rep != 0);
281 // Create address:
|
282 karl 1.91
|
283 kumpf 1.92 memset(_rep->address, 0, sizeof(*_rep->address));
|
284 karl 1.91
|
285 kumpf 1.92 if (_localConnection)
286 {
|
287 karl 1.91 #ifndef PEGASUS_DISABLE_LOCAL_DOMAIN_SOCKET
|
288 kumpf 1.92 reinterpret_cast<struct sockaddr_un*>(_rep->address)->sun_family =
289 AF_UNIX;
290 strcpy(reinterpret_cast<struct sockaddr_un*>(_rep->address)->sun_path,
291 PEGASUS_LOCAL_DOMAIN_SOCKET_PATH);
|
292 karl 1.91 #ifdef PEGASUS_PLATFORM_OS400_ISERIES_IBM
|
293 kumpf 1.92 AtoE(reinterpret_cast<struct sockaddr_un*>(_rep->address)->sun_path);
|
294 karl 1.91 #endif
|
295 kumpf 1.92 ::unlink(
296 reinterpret_cast<struct sockaddr_un*>(_rep->address)->sun_path);
|
297 karl 1.91 #else
|
298 kumpf 1.92 PEGASUS_ASSERT(false);
|
299 karl 1.91 #endif
|
300 kumpf 1.92 }
301 else
302 {
303 reinterpret_cast<struct sockaddr_in*>(_rep->address)->sin_addr.s_addr =
304 INADDR_ANY;
305 reinterpret_cast<struct sockaddr_in*>(_rep->address)->sin_family =
306 AF_INET;
307 reinterpret_cast<struct sockaddr_in*>(_rep->address)->sin_port =
308 htons(_portNumber);
309 }
310
311 // Create socket:
312
313 if (_localConnection)
314 {
315 _rep->socket = Socket::createSocket(AF_UNIX, SOCK_STREAM, 0);
316 }
317 else
318 {
319 _rep->socket = Socket::createSocket(PF_INET, SOCK_STREAM, IPPROTO_TCP);
320 }
321 kumpf 1.92
322 if (_rep->socket < 0)
323 {
324 delete _rep;
325 _rep = 0;
326 MessageLoaderParms parms("Common.HTTPAcceptor.FAILED_CREATE_SOCKET",
327 "Failed to create socket");
328 Tracer::trace(TRC_DISCARDED_DATA, Tracer::LEVEL2,
329 "HTTPAcceptor::_bind _rep->socket < 0");
330 throw BindFailedException(parms);
331 }
|
332 karl 1.91
333
334 // set the close-on-exec bit for this file handle.
335 // any unix that forks needs this bit set.
336 #if !defined PEGASUS_OS_TYPE_WINDOWS && !defined(PEGASUS_OS_VMS)
|
337 kumpf 1.92 int sock_flags;
338 if ((sock_flags = fcntl(_rep->socket, F_GETFD, 0)) < 0)
339 {
340 PEG_TRACE_STRING(TRC_DISCARDED_DATA, Tracer::LEVEL2,
341 "HTTPAcceptor::_bind: fcntl(F_GETFD) failed");
342 }
343 else
344 {
345 sock_flags |= FD_CLOEXEC;
346 if (fcntl(_rep->socket, F_SETFD, sock_flags) < 0)
347 {
348 PEG_TRACE_STRING(TRC_DISCARDED_DATA, Tracer::LEVEL2,
349 "HTTPAcceptor::_bind: fcntl(F_SETFD) failed");
350 }
351 }
352 #endif
353
354
355 //
356 // Set the socket option SO_REUSEADDR to reuse the socket address so
357 // that we can rebind to a new socket using the same address when we
358 kumpf 1.92 // need to resume the cimom as a result of a timeout during a Shutdown
359 // operation.
360 //
361 int opt=1;
362 if (setsockopt(_rep->socket, SOL_SOCKET, SO_REUSEADDR,
363 (char *)&opt, sizeof(opt)) < 0)
364 {
365 Socket::close(_rep->socket);
366 delete _rep;
367 _rep = 0;
368 MessageLoaderParms parms("Common.HTTPAcceptor.FAILED_SET_SOCKET_OPTION",
369 "Failed to set socket option");
370 PEG_TRACE_STRING(TRC_DISCARDED_DATA, Tracer::LEVEL2,
371 "HTTPAcceptor::_bind: Failed to set socket option.");
372 throw BindFailedException(parms);
373 }
374
375
376 //
377 // Bind socket to port:
378 //
379 kumpf 1.92 if (::bind(_rep->socket, _rep->address, _rep->address_size) < 0)
380 {
381 Socket::close(_rep->socket);
382 delete _rep;
383 _rep = 0;
384 MessageLoaderParms parms("Common.HTTPAcceptor.FAILED_BIND_SOCKET",
385 "Failed to bind socket");
386 PEG_TRACE_STRING(TRC_DISCARDED_DATA, Tracer::LEVEL2,
387 "HTTPAcceptor::_bind: Failed to bind socket.");
388 throw BindFailedException(parms);
389 }
390
391
392 //
393 // Get the actual port value used if the caller specified a port value of 0.
394 //
395 if (_portNumber == 0)
396 {
397 sockaddr_in buf;
398 SocketLength bufSize = sizeof(buf);
399 if (getsockname(_rep->socket, reinterpret_cast<sockaddr *>(&buf),
400 kumpf 1.92 &bufSize) == 0 )
401 {
402 _portNumber = ntohs(buf.sin_port);
403 }
404 }
405
406
407 //
408 // Change permissions on Linux local domain socket to allow writes by
409 // others.
410 //
|
411 karl 1.91 #if !defined(PEGASUS_DISABLE_LOCAL_DOMAIN_SOCKET) && \
|
412 kumpf 1.92 (defined(PEGASUS_PLATFORM_LINUX_GENERIC_GNU) || \
413 defined(PEGASUS_PLATFORM_ZOS_ZSERIES_IBM))
414 if (_localConnection)
415 {
416 if (::chmod(PEGASUS_LOCAL_DOMAIN_SOCKET_PATH,
417 S_IRUSR | S_IWUSR | S_IXUSR |
418 S_IRGRP | S_IWGRP | S_IXGRP |
419 S_IROTH | S_IWOTH | S_IXOTH ) < 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 PEG_TRACE_STRING(TRC_DISCARDED_DATA, Tracer::LEVEL2,
427 "HTTPAcceptor::_bind: Failed to set domain socket "
428 "permissions.");
429 throw BindFailedException(parms);
430 }
431 }
432 #endif
433 kumpf 1.92
434 // Set up listening on the given socket:
435
436 //int const MAX_CONNECTION_QUEUE_LENGTH = 15;
437
438 if (listen(_rep->socket, MAX_CONNECTION_QUEUE_LENGTH) < 0)
439 {
440 Socket::close(_rep->socket);
441 delete _rep;
442 _rep = 0;
443 MessageLoaderParms parms("Common.HTTPAcceptor.FAILED_BIND_SOCKET",
444 "Failed to bind socket");
445 PEG_TRACE_STRING(TRC_DISCARDED_DATA, Tracer::LEVEL2,
446 "HTTPAcceptor::_bind: Failed to bind socket(1).");
447 throw BindFailedException(parms);
448 }
449
450 // Register to receive SocketMessages on this socket:
451
452 if (-1 == ( _entry_index = _monitor->solicitSocketMessages(
453 _rep->socket,
454 kumpf 1.92 SocketMessage::READ | SocketMessage::EXCEPTION,
455 getQueueId(),
456 Monitor::ACCEPTOR)))
457 {
458 Socket::close(_rep->socket);
459 delete _rep;
460 _rep = 0;
461 MessageLoaderParms parms(
462 "Common.HTTPAcceptor.FAILED_SOLICIT_SOCKET_MESSAGES",
463 "Failed to solicit socket messaeges");
464 PEG_TRACE_STRING(TRC_DISCARDED_DATA, Tracer::LEVEL2,
465 "HTTPAcceptor::_bind: Failed to solicit socket messages(2).");
466 throw BindFailedException(parms);
467 }
|
468 karl 1.91 }
469
470 /**
|
471 kumpf 1.92 closeConnectionSocket - close the server listening socket to disallow
472 new client connections.
|
473 karl 1.91 */
474 void HTTPAcceptor::closeConnectionSocket()
475 {
|
476 kumpf 1.92 if (_rep)
477 {
478 // unregister the socket
479
480 // ATTN - comment out - see CIMServer::stopClientConnection()
481 //_monitor->unsolicitSocketMessages(_rep->socket);
482
483 // close the socket
484 Socket::close(_rep->socket);
485 // Unlink Local Domain Socket Bug# 3312
486 if (_localConnection)
487 {
|
488 karl 1.91 #ifndef PEGASUS_DISABLE_LOCAL_DOMAIN_SOCKET
|
489 kumpf 1.92 PEG_TRACE_STRING(TRC_HTTP, Tracer::LEVEL2,
490 "HTTPAcceptor::closeConnectionSocket Unlinking local "
491 "connection.");
492 ::unlink(
493 reinterpret_cast<struct sockaddr_un*>(_rep->address)->sun_path);
|
494 karl 1.91 #else
|
495 kumpf 1.92 PEGASUS_ASSERT(false);
|
496 karl 1.91 #endif
|
497 kumpf 1.92 }
498 }
499 else
500 {
501 PEG_TRACE_STRING(TRC_DISCARDED_DATA, Tracer::LEVEL2,
502 "HTTPAcceptor::closeConnectionSocket failure _rep is null.");
503 }
|
504 karl 1.91 }
505
506 /**
507 reopenConnectionSocket - creates a new server socket.
508 */
509 void HTTPAcceptor::reopenConnectionSocket()
510 {
|
511 kumpf 1.92 if (_rep)
512 {
513 _bind();
514 }
515 else
516 {
517 PEG_TRACE_STRING(TRC_DISCARDED_DATA, Tracer::LEVEL2,
518 "HTTPAcceptor::reopenConnectionSocket failure _rep is null.");
519 }
|
520 karl 1.91 }
521
522
523 /**
524 reconnectConnectionSocket - creates a new server socket.
525 */
526 void HTTPAcceptor::reconnectConnectionSocket()
527 {
|
528 kumpf 1.92 if (_rep)
529 {
530 // unregister the socket
531 _monitor->unsolicitSocketMessages(_rep->socket);
532 // close the socket
533 Socket::close(_rep->socket);
534 // Unlink Local Domain Socket Bug# 3312
535 if (_localConnection)
536 {
|
537 karl 1.91 #ifndef PEGASUS_DISABLE_LOCAL_DOMAIN_SOCKET
|
538 kumpf 1.92 PEG_TRACE_STRING(TRC_HTTP, Tracer::LEVEL2,
539 "HTTPAcceptor::reconnectConnectionSocket Unlinking local "
540 "connection." );
541 ::unlink(
542 reinterpret_cast<struct sockaddr_un*>(_rep->address)->sun_path);
|
543 karl 1.91 #else
|
544 kumpf 1.92 PEGASUS_ASSERT(false);
|
545 karl 1.91 #endif
|
546 kumpf 1.92 }
547 // open the socket
548 _bind();
549 }
550 else
551 {
552 PEG_TRACE_STRING(TRC_DISCARDED_DATA, Tracer::LEVEL2,
553 "HTTPAcceptor::reconnectConnectionSocket failure _rep is null.");
554 }
|
555 karl 1.91 }
556
557 /**
|
558 kumpf 1.92 getOutstandingRequestCount - returns the number of outstanding requests.
|
559 karl 1.91 */
560 Uint32 HTTPAcceptor::getOutstandingRequestCount() const
561 {
|
562 kumpf 1.92 Uint32 count = 0;
563 if (_rep)
564 {
565 AutoMutex autoMut(_rep->_connection_mut);
566 if (_rep->connections.size() > 0)
567 {
568 HTTPConnection* connection = _rep->connections[0];
569 count = connection->getRequestCount();
570 }
571 }
572 return count;
|
573 karl 1.91 }
574
575
576 /**
577 getPortNumber - returns the port number used for the connection
578 */
579 Uint32 HTTPAcceptor::getPortNumber() const
580 {
581 return _portNumber;
582 }
583
584 void HTTPAcceptor::setSocketWriteTimeout(Uint32 socketWriteTimeout)
585 {
586 _socketWriteTimeout = socketWriteTimeout;
587 }
588
589 void HTTPAcceptor::unbind()
590 {
|
591 kumpf 1.92 if (_rep)
592 {
593 _portNumber = 0;
594 Socket::close(_rep->socket);
|
595 karl 1.91
|
596 kumpf 1.92 if (_localConnection)
597 {
|
598 karl 1.91 #ifndef PEGASUS_DISABLE_LOCAL_DOMAIN_SOCKET
|
599 kumpf 1.92 ::unlink(
600 reinterpret_cast<struct sockaddr_un*>(_rep->address)->sun_path);
|
601 karl 1.91 #else
|
602 kumpf 1.92 PEGASUS_ASSERT(false);
|
603 karl 1.91 #endif
|
604 kumpf 1.92 }
|
605 karl 1.91
|
606 kumpf 1.92 delete _rep;
607 _rep = 0;
608 }
609 else
610 {
611 PEG_TRACE_STRING(TRC_DISCARDED_DATA, Tracer::LEVEL2,
612 "HTTPAcceptor::unbind failure _rep is null." );
613 }
|
614 karl 1.91 }
615
616 void HTTPAcceptor::destroyConnections()
617 {
|
618 kumpf 1.92 if (_rep)
619 {
620 // For each connection created by this object:
|
621 karl 1.91
|
622 kumpf 1.92 AutoMutex autoMut(_rep->_connection_mut);
623 for (Uint32 i = 0, n = _rep->connections.size(); i < n; i++)
624 {
625 HTTPConnection* connection = _rep->connections[i];
626 SocketHandle socket = connection->getSocket();
|
627 karl 1.91
|
628 kumpf 1.92 // Unsolicit SocketMessages:
|
629 karl 1.91
|
630 kumpf 1.92 _monitor->unsolicitSocketMessages(socket);
|
631 karl 1.91
|
632 kumpf 1.92 // Destroy the connection (causing it to close):
|
633 karl 1.91
|
634 kumpf 1.92 while (connection->refcount.get()) { }
635 delete connection;
636 }
|
637 karl 1.91
|
638 kumpf 1.92 _rep->connections.clear();
639 }
|
640 karl 1.91 }
641
642 void HTTPAcceptor::_acceptConnection()
643 {
|
644 kumpf 1.92 // This function cannot be called on an invalid socket!
|
645 karl 1.91
|
646 kumpf 1.92 PEGASUS_ASSERT(_rep != 0);
|
647 karl 1.91
|
648 kumpf 1.92 // Accept the connection (populate the address):
|
649 karl 1.91
|
650 kumpf 1.92 struct sockaddr* accept_address;
651 SocketLength address_size;
|
652 karl 1.91
|
653 kumpf 1.92 if (_localConnection)
654 {
|
655 karl 1.91 #ifndef PEGASUS_DISABLE_LOCAL_DOMAIN_SOCKET
|
656 kumpf 1.92 accept_address =
657 reinterpret_cast<struct sockaddr*>(new struct sockaddr_un);
658 address_size = sizeof(struct sockaddr_un);
|
659 karl 1.91 #else
|
660 kumpf 1.92 PEGASUS_ASSERT(false);
|
661 karl 1.91 #endif
|
662 kumpf 1.92 }
663 else
664 {
665 accept_address =
666 reinterpret_cast<struct sockaddr*>(new struct sockaddr_in);
667 address_size = sizeof(struct sockaddr_in);
668 }
669
670 SocketHandle socket = accept(_rep->socket, accept_address, &address_size);
671
672 if (socket == PEGASUS_SOCKET_ERROR)
673 {
674 // the remote connection is invalid, destroy client address.
675 delete accept_address;
676
677 // TCPIP is down reconnect this acceptor
678 if (getSocketError() == PEGASUS_NETWORK_TCPIP_STOPPED)
679 {
680 PEG_TRACE_STRING(TRC_DISCARDED_DATA, Tracer::LEVEL2,
681 "Socket has an IO error. TCP/IP down. Try to reconnect.");
682
683 kumpf 1.92 reconnectConnectionSocket();
684
685 return;
686 }
|
687 karl 1.91
|
688 kumpf 1.92 Logger::put(Logger::STANDARD_LOG, System::CIMSERVER, Logger::TRACE,
689 "HTTPAcceptor - accept() failure. errno: $0", errno);
|
690 karl 1.91
|
691 kumpf 1.92 PEG_TRACE_STRING(TRC_DISCARDED_DATA, Tracer::LEVEL2,
692 "HTTPAcceptor: accept() failed");
693 return;
694 }
|
695 karl 1.91
|
696 kumpf 1.92 String ipAddress;
|
697 karl 1.91
|
698 kumpf 1.92 if (_localConnection)
699 {
700 ipAddress = "localhost";
701 }
702 else
703 {
704 unsigned char* sa = reinterpret_cast<unsigned char*>(
705 &reinterpret_cast<struct sockaddr_in*>(
706 accept_address)->sin_addr.s_addr);
707 char ipBuffer[32];
708 sprintf(ipBuffer, "%u.%u.%u.%u", sa[0], sa[1], sa[2], sa[3]);
709 ipAddress = ipBuffer;
710 }
|
711 karl 1.91
|
712 kumpf 1.92 delete accept_address;
|
713 karl 1.91
714 // set the close on exec flag
715 #if !defined(PEGASUS_OS_TYPE_WINDOWS) && !defined(PEGASUS_OS_VMS)
|
716 kumpf 1.92 int sock_flags;
717 if ((sock_flags = fcntl(socket, F_GETFD, 0)) < 0)
718 {
719 PEG_TRACE_STRING(TRC_DISCARDED_DATA, Tracer::LEVEL2,
720 "HTTPAcceptor: fcntl(F_GETFD) failed");
721 }
722 else
723 {
724 sock_flags |= FD_CLOEXEC;
725 if (fcntl(socket, F_SETFD, sock_flags) < 0)
726 {
727 PEG_TRACE_STRING(TRC_DISCARDED_DATA, Tracer::LEVEL2,
728 "HTTPAcceptor: fcntl(F_SETFD) failed");
729 }
730 }
|
731 karl 1.91 #endif
732
733
|
734 kumpf 1.92 PEG_LOGGER_TRACE((Logger::STANDARD_LOG, System::CIMSERVER, 0,
735 "HTTPAcceptor - accept() success. Socket: $1" ,socket));
736
737 AutoPtr<MP_Socket> mp_socket(new MP_Socket(
738 socket, _sslcontext, _sslContextObjectLock));
739
740 mp_socket->setSocketWriteTimeout(_socketWriteTimeout);
741
742 // Perform the SSL handshake, if applicable. Make the socket non-blocking
743 // for this operation so we can send it back to the Monitor's select() loop
744 // if it takes a while.
745
746 mp_socket->disableBlocking();
747 Sint32 socketAcceptStatus = mp_socket->accept();
748 mp_socket->enableBlocking();
749
750 if (socketAcceptStatus < 0)
751 {
752 PEG_TRACE_STRING(TRC_DISCARDED_DATA, Tracer::LEVEL2,
753 "HTTPAcceptor: SSL_accept() failed");
754 mp_socket->close();
755 kumpf 1.92 return;
756 }
757
758 // Create a new connection and add it to the connection list:
759
760 HTTPConnection* connection = new HTTPConnection(_monitor, mp_socket,
761 ipAddress, this, static_cast<MessageQueue *>(_outputMessageQueue));
762
763 if (socketAcceptStatus == 0)
764 {
765 PEG_TRACE_STRING(TRC_HTTP, Tracer::LEVEL2,
766 "HTTPAcceptor: SSL_accept() pending");
767 connection->_acceptPending = true;
768 }
|
769 karl 1.91
|
770 kumpf 1.92 // Solicit events on this new connection's socket:
771 int index;
|
772 karl 1.91
|
773 kumpf 1.92 if (-1 == (index = _monitor->solicitSocketMessages(
774 connection->getSocket(),
775 SocketMessage::READ | SocketMessage::EXCEPTION,
776 connection->getQueueId(), Monitor::CONNECTION)) )
777 {
778 // ATTN-DE-P2-2003100503::TODO::Need to enhance code to return
779 // an error message to Client application.
780 Tracer::trace(TRC_DISCARDED_DATA, Tracer::LEVEL2,
781 "HTTPAcceptor::_acceptConnection: Attempt to allocate entry in "
782 "_entries table failed.");
783 delete connection;
784 Socket::close(socket);
785 return;
786 }
|
787 karl 1.91
|
788 kumpf 1.92 // Save the socket for cleanup later:
789 connection->_entry_index = index;
790 AutoMutex autoMut(_rep->_connection_mut);
791 _rep->connections.append(connection);
|
792 karl 1.91 }
793
|
794 kumpf 1.92 PEGASUS_NAMESPACE_END
|