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