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