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.101 #include "HostAddress.h"
|
44 karl 1.91 #include "Tracer.h"
|
45 kumpf 1.93 #include <Pegasus/Common/MessageLoader.h>
|
46 karl 1.91
|
47 ouyang.jian 1.102 #ifdef PEGASUS_OS_PASE
48 # include <as400_protos.h>
49 # include <Pegasus/Common/PaseCcsid.h>
50 #endif
51
|
52 karl 1.91 PEGASUS_USING_STD;
53
54 PEGASUS_NAMESPACE_BEGIN
55
56
|
57 mateus.baur 1.103 static int _maxConnectionQueueLength = -1;
|
58 karl 1.91
59 ////////////////////////////////////////////////////////////////////////////////
60 //
61 // HTTPAcceptorRep
62 //
63 ////////////////////////////////////////////////////////////////////////////////
64
65 class HTTPAcceptorRep
66 {
67 public:
|
68 dave.sudlik 1.101 HTTPAcceptorRep(Uint16 connectionType)
|
69 karl 1.91 {
|
70 dave.sudlik 1.101 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.101 #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.101 else
95 {
96 PEGASUS_ASSERT(false);
|
97 karl 1.91 }
|
98 dave.sudlik 1.101 }
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.101 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.101 _connectionType(connectionType),
|
132 karl 1.91 _portNumber(portNumber),
133 _sslcontext(sslcontext),
|
134 dave.sudlik 1.108 _sslContextObjectLock(sslContextObjectLock),
135 _idleConnectionTimeoutSeconds(0)
|
136 karl 1.91 {
137 Socket::initializeInterface();
138
139 /*
|
140 mateus.baur 1.103 Platforms interpret the value of _maxConnectionQueueLength
|
141 kumpf 1.92 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 mateus.baur 1.103 _maxConnectionQueueLength = 15.
|
149 karl 1.91 */
150
|
151 kumpf 1.92 //To engage runtime backlog queue length: uncomment the following block AND
|
152 mateus.baur 1.103 //comment out the line _maxConnectionQueueLength = 15
|
153 karl 1.91
154 /*
|
155 mateus.baur 1.103 if (_maxConnectionQueueLength == -1)
|
156 kumpf 1.92 {
157 const char* env = getenv("PEGASUS_MAX_BACKLOG_CONNECTION_QUEUE");
158 if (!env)
159 {
|
160 mateus.baur 1.103 _maxConnectionQueueLength = 15;
|
161 kumpf 1.92 }
162 else
163 {
164 char* end = NULL;
|
165 mateus.baur 1.103 _maxConnectionQueueLength = strtol(env, &end, 10);
|
166 kumpf 1.92 if (*end)
|
167 mateus.baur 1.103 _maxConnectionQueueLength = 15;
168 cout << " _maxConnectionQueueLength = " <<
169 _maxConnectionQueueLength << endl;
|
170 kumpf 1.92 }
|
171 karl 1.91 }
172 */
|
173 mateus.baur 1.103 #ifdef PEGASUS_WMIMAPPER
174 //The WMI Mapper can be used as a proxy to multiple WMI Servers.
175 //If a client application simultaneously initiates connections
176 //to many Windows systems, many of these connections may be routed
177 //to a single WMI Mapper. A larger _maxConnectionQueueLength
178 //value is required to allow these connections to be initiated
179 //successfully.
180 _maxConnectionQueueLength = 40;
181 #else
182 _maxConnectionQueueLength = 15;
183 #endif
|
184 karl 1.91 }
185
186 HTTPAcceptor::~HTTPAcceptor()
187 {
|
188 kumpf 1.92 destroyConnections();
189 unbind();
190 // ATTN: Is this correct in a multi-HTTPAcceptor server?
191 Socket::uninitializeInterface();
|
192 karl 1.91 }
193
194 void HTTPAcceptor::handleEnqueue(Message *message)
195 {
|
196 kumpf 1.92 if (!message)
197 return;
198
199 PEGASUS_ASSERT(_rep != 0);
200 switch (message->getType())
201 {
202 case SOCKET_MESSAGE:
203 {
204 SocketMessage* socketMessage = (SocketMessage*)message;
205
206 // If this is a connection request:
207
208 if (socketMessage->socket == _rep->socket &&
209 socketMessage->events & SocketMessage::READ)
210 {
211 _acceptConnection();
212 }
213 else
214 {
215 // ATTN! this can't happen!
|
216 marek 1.95 PEG_TRACE_CSTRING(TRC_DISCARDED_DATA, Tracer::LEVEL2,
|
217 kumpf 1.92 "HTTPAcceptor::handleEnqueue: Invalid SOCKET_MESSAGE "
218 "received.");
219 }
|
220 karl 1.91
221 break;
|
222 kumpf 1.92 }
223
224 case CLOSE_CONNECTION_MESSAGE:
225 {
226 CloseConnectionMessage* closeConnectionMessage =
227 (CloseConnectionMessage*)message;
228
229 AutoMutex autoMut(_rep->_connection_mut);
230
231 for (Uint32 i = 0, n = _rep->connections.size(); i < n; i++)
232 {
233 HTTPConnection* connection = _rep->connections[i];
234 SocketHandle socket = connection->getSocket();
235
236 if (socket == closeConnectionMessage->socket)
237 {
238 _monitor->unsolicitSocketMessages(socket);
239 _rep->connections.remove(i);
240 delete connection;
241 break;
242 }
243 kumpf 1.92 }
|
244 karl 1.91
|
245 kumpf 1.92 break;
246 }
|
247 karl 1.91
|
248 kumpf 1.92 default:
249 // ATTN: need unexpected message error!
|
250 marek 1.95 PEG_TRACE_CSTRING(TRC_DISCARDED_DATA, Tracer::LEVEL2,
|
251 kumpf 1.92 "HTTPAcceptor::handleEnqueue: Invalid MESSAGE received.");
252 break;
253 }
|
254 karl 1.91
|
255 kumpf 1.92 delete message;
|
256 karl 1.91 }
257
258
259 void HTTPAcceptor::handleEnqueue()
260 {
|
261 kumpf 1.92 Message* message = dequeue();
|
262 karl 1.91
|
263 kumpf 1.92 if (!message)
264 {
|
265 marek 1.95 PEG_TRACE_CSTRING(TRC_DISCARDED_DATA, Tracer::LEVEL2,
|
266 kumpf 1.92 "HTTPAcceptor::handleEnqueue(): No message on queue.");
267 return;
268 }
|
269 karl 1.91
|
270 kumpf 1.92 handleEnqueue(message);
|
271 karl 1.91 }
272
273 void HTTPAcceptor::bind()
274 {
|
275 kumpf 1.92 if (_rep)
276 {
277 MessageLoaderParms parms("Common.HTTPAcceptor.ALREADY_BOUND",
278 "HTTPAcceptor already bound");
|
279 karl 1.91
|
280 marek 1.95 PEG_TRACE_CSTRING(TRC_DISCARDED_DATA, Tracer::LEVEL2,
|
281 kumpf 1.92 "HTTPAcceptor::bind: HTTPAcceptor already bound.");
282 throw BindFailedException(parms);
283 }
|
284 karl 1.91
|
285 dave.sudlik 1.101 _rep = new HTTPAcceptorRep(_connectionType);
|
286 karl 1.91
|
287 kumpf 1.92 // bind address
288 _bind();
|
289 karl 1.91 }
290
291 /**
|
292 kumpf 1.92 _bind - creates a new server socket and bind socket to the port address.
293 If PEGASUS_DISABLE_LOCAL_DOMAIN_SOCKET is not defined, the port number is
294 ignored and a domain socket is bound.
|
295 karl 1.91 */
296 void HTTPAcceptor::_bind()
297 {
|
298 ouyang.jian 1.102 #ifdef PEGASUS_OS_PASE
299 // bind need ccsid is 819
300 int orig_ccsid;
301 orig_ccsid = _SETCCSID(-1);
302 if (orig_ccsid == -1)
303 {
304 PEG_TRACE_STRING(TRC_DISCARDED_DATA, Tracer::LEVEL2,
305 String("HTTPAcceptor::_bind: Can not get current PASE CCSID."));
306 orig_ccsid = 1208;
307 }
308 PaseCcsid ccsid(819, orig_ccsid);
309 #endif
310
|
311 kumpf 1.92 PEGASUS_ASSERT(_rep != 0);
312 // Create address:
|
313 dave.sudlik 1.101 memset(_rep->address, 0, _rep->address_size);
|
314 karl 1.91
|
315 dave.sudlik 1.101 if (_connectionType == LOCAL_CONNECTION)
|
316 kumpf 1.92 {
|
317 karl 1.91 #ifndef PEGASUS_DISABLE_LOCAL_DOMAIN_SOCKET
|
318 kumpf 1.100 //
319 // Make sure the local domain socket can be owned by the cimserver
320 // user. Otherwise, the bind may fail with a vague "bind failed"
321 // error.
322 //
323 if (System::exists(PEGASUS_LOCAL_DOMAIN_SOCKET_PATH))
324 {
325 if (!System::removeFile(PEGASUS_LOCAL_DOMAIN_SOCKET_PATH))
326 {
327 throw CannotRemoveFile(PEGASUS_LOCAL_DOMAIN_SOCKET_PATH);
328 }
329 }
330
|
331 kumpf 1.92 reinterpret_cast<struct sockaddr_un*>(_rep->address)->sun_family =
332 AF_UNIX;
333 strcpy(reinterpret_cast<struct sockaddr_un*>(_rep->address)->sun_path,
334 PEGASUS_LOCAL_DOMAIN_SOCKET_PATH);
|
335 karl 1.91 #else
|
336 kumpf 1.92 PEGASUS_ASSERT(false);
|
337 karl 1.91 #endif
|
338 kumpf 1.92 }
|
339 dave.sudlik 1.101 #ifdef PEGASUS_ENABLE_IPV6
340 else if (_connectionType == IPV6_CONNECTION)
341 {
342 reinterpret_cast<struct sockaddr_in6*>(_rep->address)->sin6_addr =
343 in6addr_any;
344 reinterpret_cast<struct sockaddr_in6*>(_rep->address)->sin6_family =
345 AF_INET6;
346 reinterpret_cast<struct sockaddr_in6*>(_rep->address)->sin6_port =
347 htons(_portNumber);
348 }
349 #endif
350 else if(_connectionType == IPV4_CONNECTION)
|
351 kumpf 1.92 {
352 reinterpret_cast<struct sockaddr_in*>(_rep->address)->sin_addr.s_addr =
353 INADDR_ANY;
354 reinterpret_cast<struct sockaddr_in*>(_rep->address)->sin_family =
355 AF_INET;
356 reinterpret_cast<struct sockaddr_in*>(_rep->address)->sin_port =
357 htons(_portNumber);
358 }
|
359 dave.sudlik 1.101 else
360 {
361 PEGASUS_ASSERT(false);
362 }
|
363 kumpf 1.92
364 // Create socket:
365
|
366 dave.sudlik 1.101 if (_connectionType == LOCAL_CONNECTION)
|
367 kumpf 1.92 {
368 _rep->socket = Socket::createSocket(AF_UNIX, SOCK_STREAM, 0);
369 }
|
370 dave.sudlik 1.101 #ifdef PEGASUS_ENABLE_IPV6
371 else if (_connectionType == IPV6_CONNECTION)
372 {
373 _rep->socket = Socket::createSocket(PF_INET6, SOCK_STREAM, IPPROTO_TCP);
374 }
375 #endif
376 else if (_connectionType == IPV4_CONNECTION)
377 {
378 _rep->socket = Socket::createSocket(PF_INET, SOCK_STREAM, IPPROTO_TCP);
379 }
|
380 kumpf 1.92 else
381 {
|
382 dave.sudlik 1.101 PEGASUS_ASSERT(false);
|
383 kumpf 1.92 }
384
385 if (_rep->socket < 0)
386 {
387 delete _rep;
388 _rep = 0;
389 MessageLoaderParms parms("Common.HTTPAcceptor.FAILED_CREATE_SOCKET",
390 "Failed to create socket");
|
391 marek 1.95 PEG_TRACE_CSTRING(TRC_DISCARDED_DATA, Tracer::LEVEL2,
|
392 thilo.boehm 1.115 "HTTPAcceptor::_bind: createSocket() _rep->socket failed");
|
393 kumpf 1.92 throw BindFailedException(parms);
394 }
|
395 karl 1.91
|
396 kumpf 1.109 Socket::disableBlocking(_rep->socket);
|
397 karl 1.91
398 // set the close-on-exec bit for this file handle.
399 // any unix that forks needs this bit set.
400 #if !defined PEGASUS_OS_TYPE_WINDOWS && !defined(PEGASUS_OS_VMS)
|
401 kumpf 1.92 int sock_flags;
402 if ((sock_flags = fcntl(_rep->socket, F_GETFD, 0)) < 0)
403 {
|
404 marek 1.95 PEG_TRACE_CSTRING(TRC_DISCARDED_DATA, Tracer::LEVEL2,
|
405 kumpf 1.92 "HTTPAcceptor::_bind: fcntl(F_GETFD) failed");
406 }
407 else
408 {
409 sock_flags |= FD_CLOEXEC;
410 if (fcntl(_rep->socket, F_SETFD, sock_flags) < 0)
411 {
|
412 marek 1.95 PEG_TRACE_CSTRING(TRC_DISCARDED_DATA, Tracer::LEVEL2,
|
413 kumpf 1.92 "HTTPAcceptor::_bind: fcntl(F_SETFD) failed");
414 }
415 }
416 #endif
417
418
419 //
420 // Set the socket option SO_REUSEADDR to reuse the socket address so
421 // that we can rebind to a new socket using the same address when we
422 // need to resume the cimom as a result of a timeout during a Shutdown
423 // operation.
424 //
425 int opt=1;
426 if (setsockopt(_rep->socket, SOL_SOCKET, SO_REUSEADDR,
427 (char *)&opt, sizeof(opt)) < 0)
428 {
429 Socket::close(_rep->socket);
430 delete _rep;
431 _rep = 0;
432 MessageLoaderParms parms("Common.HTTPAcceptor.FAILED_SET_SOCKET_OPTION",
433 "Failed to set socket option");
|
434 marek 1.95 PEG_TRACE_CSTRING(TRC_DISCARDED_DATA, Tracer::LEVEL2,
|
435 kumpf 1.92 "HTTPAcceptor::_bind: Failed to set socket option.");
436 throw BindFailedException(parms);
437 }
438
439
440 //
441 // Bind socket to port:
442 //
443 if (::bind(_rep->socket, _rep->address, _rep->address_size) < 0)
444 {
|
445 thilo.boehm 1.115 MessageLoaderParms parms(
446 "Common.HTTPAcceptor.FAILED_BIND_SOCKET_DETAIL",
447 "Failed to bind socket on port $0: $1.",
448 _portNumber, PEGASUS_SYSTEM_NETWORK_ERRORMSG_NLS);
449
|
450 kumpf 1.92 Socket::close(_rep->socket);
451 delete _rep;
452 _rep = 0;
|
453 marek 1.95 PEG_TRACE_CSTRING(TRC_DISCARDED_DATA, Tracer::LEVEL2,
|
454 kumpf 1.92 "HTTPAcceptor::_bind: Failed to bind socket.");
455 throw BindFailedException(parms);
456 }
457
458
459 //
460 // Get the actual port value used if the caller specified a port value of 0.
461 //
462 if (_portNumber == 0)
463 {
464 sockaddr_in buf;
465 SocketLength bufSize = sizeof(buf);
466 if (getsockname(_rep->socket, reinterpret_cast<sockaddr *>(&buf),
467 &bufSize) == 0 )
468 {
469 _portNumber = ntohs(buf.sin_port);
470 }
471 }
472
473
474 //
475 kumpf 1.92 // Change permissions on Linux local domain socket to allow writes by
476 // others.
477 //
|
478 karl 1.91 #if !defined(PEGASUS_DISABLE_LOCAL_DOMAIN_SOCKET) && \
|
479 kumpf 1.92 (defined(PEGASUS_PLATFORM_LINUX_GENERIC_GNU) || \
480 defined(PEGASUS_PLATFORM_ZOS_ZSERIES_IBM))
|
481 dave.sudlik 1.101 if (_connectionType == LOCAL_CONNECTION)
|
482 kumpf 1.92 {
483 if (::chmod(PEGASUS_LOCAL_DOMAIN_SOCKET_PATH,
484 S_IRUSR | S_IWUSR | S_IXUSR |
485 S_IRGRP | S_IWGRP | S_IXGRP |
486 S_IROTH | S_IWOTH | S_IXOTH ) < 0 )
487 {
|
488 thilo.boehm 1.115 MessageLoaderParms parms(
489 "Common.HTTPAcceptor.FAILED_SET_LDS_FILE_OPTION",
490 "Failed to set permission on local domain socket {0}: {1}.",
491 PEGASUS_LOCAL_DOMAIN_SOCKET_PATH,
492 PEGASUS_SYSTEM_ERRORMSG_NLS );
493
|
494 kumpf 1.92 Socket::close(_rep->socket);
495 delete _rep;
496 _rep = 0;
|
497 marek 1.95 PEG_TRACE_CSTRING(TRC_DISCARDED_DATA, Tracer::LEVEL2,
|
498 kumpf 1.92 "HTTPAcceptor::_bind: Failed to set domain socket "
499 "permissions.");
500 throw BindFailedException(parms);
501 }
502 }
503 #endif
504
505 // Set up listening on the given socket:
506
|
507 mateus.baur 1.103 //int const _maxConnectionQueueLength = 15;
|
508 kumpf 1.92
|
509 thilo.boehm 1.115 if (::listen(_rep->socket, _maxConnectionQueueLength) < 0)
|
510 kumpf 1.92 {
|
511 thilo.boehm 1.115 MessageLoaderParms parms(
512 "Common.HTTPAcceptor.FAILED_LISTEN_SOCKET",
513 "Failed to listen on socket {0}: {1}.",
514 (int)_rep->socket,PEGASUS_SYSTEM_NETWORK_ERRORMSG_NLS );
515
|
516 kumpf 1.92 Socket::close(_rep->socket);
517 delete _rep;
518 _rep = 0;
|
519 marek 1.95 PEG_TRACE_CSTRING(TRC_DISCARDED_DATA, Tracer::LEVEL2,
|
520 kumpf 1.92 "HTTPAcceptor::_bind: Failed to bind socket(1).");
521 throw BindFailedException(parms);
522 }
523
524 // Register to receive SocketMessages on this socket:
525
526 if (-1 == ( _entry_index = _monitor->solicitSocketMessages(
527 _rep->socket,
528 SocketMessage::READ | SocketMessage::EXCEPTION,
529 getQueueId(),
|
530 kumpf 1.107 MonitorEntry::TYPE_ACCEPTOR)))
|
531 kumpf 1.92 {
532 Socket::close(_rep->socket);
533 delete _rep;
534 _rep = 0;
535 MessageLoaderParms parms(
536 "Common.HTTPAcceptor.FAILED_SOLICIT_SOCKET_MESSAGES",
537 "Failed to solicit socket messaeges");
|
538 marek 1.95 PEG_TRACE_CSTRING(TRC_DISCARDED_DATA, Tracer::LEVEL2,
|
539 kumpf 1.92 "HTTPAcceptor::_bind: Failed to solicit socket messages(2).");
540 throw BindFailedException(parms);
541 }
|
542 karl 1.91 }
543
544 /**
|
545 kumpf 1.92 closeConnectionSocket - close the server listening socket to disallow
546 new client connections.
|
547 karl 1.91 */
548 void HTTPAcceptor::closeConnectionSocket()
549 {
|
550 kumpf 1.92 if (_rep)
551 {
552 // unregister the socket
553
554 // ATTN - comment out - see CIMServer::stopClientConnection()
555 //_monitor->unsolicitSocketMessages(_rep->socket);
556
557 // close the socket
558 Socket::close(_rep->socket);
559 // Unlink Local Domain Socket Bug# 3312
|
560 dave.sudlik 1.101 if (_connectionType == LOCAL_CONNECTION)
|
561 kumpf 1.92 {
|
562 karl 1.91 #ifndef PEGASUS_DISABLE_LOCAL_DOMAIN_SOCKET
|
563 marek 1.95 PEG_TRACE_CSTRING(TRC_HTTP, Tracer::LEVEL2,
|
564 kumpf 1.92 "HTTPAcceptor::closeConnectionSocket Unlinking local "
565 "connection.");
566 ::unlink(
567 reinterpret_cast<struct sockaddr_un*>(_rep->address)->sun_path);
|
568 karl 1.91 #else
|
569 kumpf 1.92 PEGASUS_ASSERT(false);
|
570 karl 1.91 #endif
|
571 kumpf 1.92 }
572 }
573 else
574 {
|
575 marek 1.95 PEG_TRACE_CSTRING(TRC_DISCARDED_DATA, Tracer::LEVEL2,
|
576 kumpf 1.92 "HTTPAcceptor::closeConnectionSocket failure _rep is null.");
577 }
|
578 karl 1.91 }
579
580 /**
581 reopenConnectionSocket - creates a new server socket.
582 */
583 void HTTPAcceptor::reopenConnectionSocket()
584 {
|
585 kumpf 1.92 if (_rep)
586 {
587 _bind();
588 }
589 else
590 {
|
591 marek 1.95 PEG_TRACE_CSTRING(TRC_DISCARDED_DATA, Tracer::LEVEL2,
|
592 kumpf 1.92 "HTTPAcceptor::reopenConnectionSocket failure _rep is null.");
593 }
|
594 karl 1.91 }
595
596
597 /**
598 reconnectConnectionSocket - creates a new server socket.
599 */
600 void HTTPAcceptor::reconnectConnectionSocket()
601 {
|
602 kumpf 1.92 if (_rep)
603 {
604 // unregister the socket
605 _monitor->unsolicitSocketMessages(_rep->socket);
606 // close the socket
607 Socket::close(_rep->socket);
608 // Unlink Local Domain Socket Bug# 3312
|
609 dave.sudlik 1.101 if (_connectionType == LOCAL_CONNECTION)
|
610 kumpf 1.92 {
|
611 karl 1.91 #ifndef PEGASUS_DISABLE_LOCAL_DOMAIN_SOCKET
|
612 marek 1.95 PEG_TRACE_CSTRING(TRC_HTTP, Tracer::LEVEL2,
|
613 kumpf 1.92 "HTTPAcceptor::reconnectConnectionSocket Unlinking local "
614 "connection." );
615 ::unlink(
616 reinterpret_cast<struct sockaddr_un*>(_rep->address)->sun_path);
|
617 karl 1.91 #else
|
618 kumpf 1.92 PEGASUS_ASSERT(false);
|
619 karl 1.91 #endif
|
620 kumpf 1.92 }
621 // open the socket
622 _bind();
623 }
624 else
625 {
|
626 marek 1.95 PEG_TRACE_CSTRING(TRC_DISCARDED_DATA, Tracer::LEVEL2,
|
627 kumpf 1.92 "HTTPAcceptor::reconnectConnectionSocket failure _rep is null.");
628 }
|
629 karl 1.91 }
630
631 /**
|
632 kumpf 1.92 getOutstandingRequestCount - returns the number of outstanding requests.
|
633 karl 1.91 */
634 Uint32 HTTPAcceptor::getOutstandingRequestCount() const
635 {
|
636 kumpf 1.92 Uint32 count = 0;
637 if (_rep)
638 {
639 AutoMutex autoMut(_rep->_connection_mut);
|
640 kumpf 1.110 for (Uint32 i = 0, n = _rep->connections.size(); i < n; i++)
|
641 kumpf 1.92 {
|
642 kumpf 1.110 HTTPConnection* connection = _rep->connections[i];
643 if (connection->isResponsePending())
644 {
645 count++;
646 }
|
647 kumpf 1.92 }
648 }
649 return count;
|
650 karl 1.91 }
651
652
653 /**
654 getPortNumber - returns the port number used for the connection
655 */
656 Uint32 HTTPAcceptor::getPortNumber() const
657 {
658 return _portNumber;
659 }
660
661 void HTTPAcceptor::setSocketWriteTimeout(Uint32 socketWriteTimeout)
662 {
663 _socketWriteTimeout = socketWriteTimeout;
664 }
665
|
666 dave.sudlik 1.108 void HTTPAcceptor::setIdleConnectionTimeout(Uint32 idleConnectionTimeoutSeconds)
667 {
668 _idleConnectionTimeoutSeconds = idleConnectionTimeoutSeconds;
669 }
670
|
671 karl 1.91 void HTTPAcceptor::unbind()
672 {
|
673 kumpf 1.92 if (_rep)
674 {
675 _portNumber = 0;
676 Socket::close(_rep->socket);
|
677 karl 1.91
|
678 dave.sudlik 1.101 if (_connectionType == LOCAL_CONNECTION)
|
679 kumpf 1.92 {
|
680 karl 1.91 #ifndef PEGASUS_DISABLE_LOCAL_DOMAIN_SOCKET
|
681 kumpf 1.92 ::unlink(
682 reinterpret_cast<struct sockaddr_un*>(_rep->address)->sun_path);
|
683 karl 1.91 #else
|
684 kumpf 1.92 PEGASUS_ASSERT(false);
|
685 karl 1.91 #endif
|
686 kumpf 1.92 }
|
687 karl 1.91
|
688 kumpf 1.92 delete _rep;
689 _rep = 0;
690 }
691 else
692 {
|
693 marek 1.95 PEG_TRACE_CSTRING(TRC_DISCARDED_DATA, Tracer::LEVEL2,
|
694 kumpf 1.92 "HTTPAcceptor::unbind failure _rep is null." );
695 }
|
696 karl 1.91 }
697
698 void HTTPAcceptor::destroyConnections()
699 {
|
700 kumpf 1.92 if (_rep)
701 {
702 // For each connection created by this object:
|
703 karl 1.91
|
704 kumpf 1.92 AutoMutex autoMut(_rep->_connection_mut);
705 for (Uint32 i = 0, n = _rep->connections.size(); i < n; i++)
706 {
707 HTTPConnection* connection = _rep->connections[i];
708 SocketHandle socket = connection->getSocket();
|
709 karl 1.91
|
710 kumpf 1.92 // Unsolicit SocketMessages:
|
711 karl 1.91
|
712 kumpf 1.92 _monitor->unsolicitSocketMessages(socket);
|
713 karl 1.91
|
714 kumpf 1.92 // Destroy the connection (causing it to close):
|
715 karl 1.91
|
716 kumpf 1.92 while (connection->refcount.get()) { }
717 delete connection;
718 }
|
719 karl 1.91
|
720 kumpf 1.92 _rep->connections.clear();
721 }
|
722 karl 1.91 }
723
724 void HTTPAcceptor::_acceptConnection()
725 {
|
726 kumpf 1.92 // This function cannot be called on an invalid socket!
|
727 karl 1.91
|
728 kumpf 1.92 PEGASUS_ASSERT(_rep != 0);
|
729 karl 1.91
|
730 kumpf 1.92 // Accept the connection (populate the address):
|
731 karl 1.91
|
732 kumpf 1.92 struct sockaddr* accept_address;
733 SocketLength address_size;
|
734 karl 1.91
|
735 dave.sudlik 1.101 if (_connectionType == LOCAL_CONNECTION)
|
736 kumpf 1.92 {
|
737 karl 1.91 #ifndef PEGASUS_DISABLE_LOCAL_DOMAIN_SOCKET
|
738 kumpf 1.92 accept_address =
739 reinterpret_cast<struct sockaddr*>(new struct sockaddr_un);
740 address_size = sizeof(struct sockaddr_un);
|
741 karl 1.91 #else
|
742 kumpf 1.92 PEGASUS_ASSERT(false);
|
743 karl 1.91 #endif
|
744 kumpf 1.92 }
745 else
746 {
|
747 dave.sudlik 1.101 #ifdef PEGASUS_ENABLE_IPV6
748 accept_address =
749 reinterpret_cast<struct sockaddr*>
750 (new struct sockaddr_storage);
751 address_size = sizeof(struct sockaddr_storage);
752 #else
|
753 kumpf 1.92 accept_address =
754 reinterpret_cast<struct sockaddr*>(new struct sockaddr_in);
755 address_size = sizeof(struct sockaddr_in);
|
756 dave.sudlik 1.101 #endif
|
757 kumpf 1.92 }
758
|
759 kumpf 1.109 // It is not necessary to handle EINTR errors from this accept() call.
760 // An EINTR error should not occur on a non-blocking socket. If the
761 // listen socket is blocking and EINTR occurs, the new socket connection
762 // is not accepted here.
763
764 // EAGAIN errors are also not handled here. An EAGAIN error should not
765 // occur after select() indicates that the listen socket is available for
766 // reading. If the accept() fails with an EAGAIN error code, a new
767 // connection is not accepted here.
768
769 SocketHandle socket = accept(_rep->socket, accept_address, &address_size);
|
770 kumpf 1.92
771 if (socket == PEGASUS_SOCKET_ERROR)
772 {
773 // the remote connection is invalid, destroy client address.
774 delete accept_address;
775
776 // TCPIP is down reconnect this acceptor
777 if (getSocketError() == PEGASUS_NETWORK_TCPIP_STOPPED)
778 {
|
779 marek 1.95 PEG_TRACE_CSTRING(TRC_DISCARDED_DATA, Tracer::LEVEL2,
|
780 kumpf 1.92 "Socket has an IO error. TCP/IP down. Try to reconnect.");
781
782 reconnectConnectionSocket();
783
784 return;
785 }
|
786 karl 1.91
|
787 kumpf 1.92 Logger::put(Logger::STANDARD_LOG, System::CIMSERVER, Logger::TRACE,
788 "HTTPAcceptor - accept() failure. errno: $0", errno);
|
789 karl 1.91
|
790 marek 1.95 PEG_TRACE_CSTRING(TRC_DISCARDED_DATA, Tracer::LEVEL2,
|
791 kumpf 1.92 "HTTPAcceptor: accept() failed");
792 return;
793 }
|
794 marek 1.114 #ifndef PEGASUS_OS_TYPE_WINDOWS
|
795 marek 1.111 // We need to ensure that the socket number is not higher than
796 // what fits into FD_SETSIZE, because we else won't be able to select on it
797 // and won't ever communicate correct on that socket.
798 if (socket >= FD_SETSIZE)
799 {
800 // the remote connection is invalid, destroy client address.
801 delete accept_address;
802
803 Logger::put(Logger::STANDARD_LOG, System::CIMSERVER, Logger::TRACE,
804 "HTTPAcceptor out of available sockets. "
805 "Closing connection to the new client.");
806
807 PEG_TRACE(
808 (TRC_DISCARDED_DATA,
809 Tracer::LEVEL2,
810 "accept() returned too large socket number %d.",
811 socket));
812
813 // close the connection
814 Socket::close(socket);
815 return;
816 marek 1.111 }
|
817 marek 1.114 #endif
|
818 karl 1.91
|
819 kumpf 1.92 String ipAddress;
|
820 karl 1.91
|
821 dave.sudlik 1.101 if (_connectionType == LOCAL_CONNECTION)
|
822 kumpf 1.92 {
823 ipAddress = "localhost";
824 }
825 else
826 {
|
827 dave.sudlik 1.101 #ifdef PEGASUS_ENABLE_IPV6
828 char ipBuffer[PEGASUS_INET6_ADDRSTR_LEN];
|
829 dmitry.mikulin 1.105 int rc;
|
830 dmitry.mikulin 1.106 if ((rc = System::getNameInfo(accept_address,
831 address_size,
832 ipBuffer,
833 PEGASUS_INET6_ADDRSTR_LEN,
834 0,
835 0,
836 NI_NUMERICHOST)))
|
837 dave.sudlik 1.101 {
838 Logger::put(Logger::STANDARD_LOG, System::CIMSERVER, Logger::TRACE,
839 "HTTPAcceptor - getnameinfo() failure. rc: $0", rc);
840
841 PEG_TRACE_CSTRING(TRC_DISCARDED_DATA, Tracer::LEVEL2,
842 "HTTPAcceptor: getnameinfo() failed");
843 delete accept_address;
844 Socket::close(socket);
845 return;
846 }
847 ipAddress = ipBuffer;
848 #else
|
849 kumpf 1.92 unsigned char* sa = reinterpret_cast<unsigned char*>(
850 &reinterpret_cast<struct sockaddr_in*>(
851 accept_address)->sin_addr.s_addr);
852 char ipBuffer[32];
853 sprintf(ipBuffer, "%u.%u.%u.%u", sa[0], sa[1], sa[2], sa[3]);
854 ipAddress = ipBuffer;
|
855 dave.sudlik 1.101 #endif
|
856 kumpf 1.92 }
|
857 karl 1.91
|
858 kumpf 1.92 delete accept_address;
|
859 karl 1.91
860 // set the close on exec flag
861 #if !defined(PEGASUS_OS_TYPE_WINDOWS) && !defined(PEGASUS_OS_VMS)
|
862 kumpf 1.92 int sock_flags;
863 if ((sock_flags = fcntl(socket, F_GETFD, 0)) < 0)
864 {
|
865 marek 1.95 PEG_TRACE_CSTRING(TRC_DISCARDED_DATA, Tracer::LEVEL2,
|
866 kumpf 1.92 "HTTPAcceptor: fcntl(F_GETFD) failed");
867 }
868 else
869 {
870 sock_flags |= FD_CLOEXEC;
871 if (fcntl(socket, F_SETFD, sock_flags) < 0)
872 {
|
873 marek 1.95 PEG_TRACE_CSTRING(TRC_DISCARDED_DATA, Tracer::LEVEL2,
|
874 kumpf 1.92 "HTTPAcceptor: fcntl(F_SETFD) failed");
875 }
876 }
|
877 karl 1.91 #endif
878
879
|
880 kumpf 1.92 PEG_LOGGER_TRACE((Logger::STANDARD_LOG, System::CIMSERVER, 0,
881 "HTTPAcceptor - accept() success. Socket: $1" ,socket));
882
|
883 kumpf 1.96 SharedPtr<MP_Socket> mp_socket(new MP_Socket(
|
884 sushma.fernandes 1.97 socket, _sslcontext, _sslContextObjectLock, ipAddress));
|
885 kumpf 1.92
|
886 kumpf 1.109 mp_socket->disableBlocking();
|
887 kumpf 1.92 mp_socket->setSocketWriteTimeout(_socketWriteTimeout);
888
|
889 kumpf 1.109 // Perform the SSL handshake, if applicable.
|
890 kumpf 1.92
891 Sint32 socketAcceptStatus = mp_socket->accept();
892
893 if (socketAcceptStatus < 0)
894 {
|
895 marek 1.95 PEG_TRACE_CSTRING(TRC_DISCARDED_DATA, Tracer::LEVEL2,
|
896 kumpf 1.92 "HTTPAcceptor: SSL_accept() failed");
897 mp_socket->close();
898 return;
899 }
900
901 // Create a new connection and add it to the connection list:
902
903 HTTPConnection* connection = new HTTPConnection(_monitor, mp_socket,
904 ipAddress, this, static_cast<MessageQueue *>(_outputMessageQueue));
905
|
906 dave.sudlik 1.108 if (_idleConnectionTimeoutSeconds)
907 {
908 connection->_idleConnectionTimeoutSeconds =
909 _idleConnectionTimeoutSeconds;
910 Time::gettimeofday(&connection->_idleStartTime);
911 }
912
|
913 kumpf 1.92 if (socketAcceptStatus == 0)
914 {
|
915 marek 1.95 PEG_TRACE_CSTRING(TRC_HTTP, Tracer::LEVEL2,
|
916 kumpf 1.92 "HTTPAcceptor: SSL_accept() pending");
917 connection->_acceptPending = true;
|
918 dave.sudlik 1.108 Time::gettimeofday(&connection->_acceptPendingStartTime);
|
919 kumpf 1.92 }
|
920 karl 1.91
|
921 kumpf 1.92 // Solicit events on this new connection's socket:
922 int index;
|
923 karl 1.91
|
924 kumpf 1.92 if (-1 == (index = _monitor->solicitSocketMessages(
925 connection->getSocket(),
926 SocketMessage::READ | SocketMessage::EXCEPTION,
|
927 kumpf 1.107 connection->getQueueId(), MonitorEntry::TYPE_CONNECTION)) )
|
928 kumpf 1.92 {
929 // ATTN-DE-P2-2003100503::TODO::Need to enhance code to return
930 // an error message to Client application.
|
931 marek 1.95 PEG_TRACE_CSTRING(TRC_DISCARDED_DATA, Tracer::LEVEL2,
|
932 kumpf 1.92 "HTTPAcceptor::_acceptConnection: Attempt to allocate entry in "
933 "_entries table failed.");
934 delete connection;
935 Socket::close(socket);
936 return;
937 }
|
938 karl 1.91
|
939 kumpf 1.92 // Save the socket for cleanup later:
940 connection->_entry_index = index;
941 AutoMutex autoMut(_rep->_connection_mut);
942 _rep->connections.append(connection);
|
943 karl 1.91 }
944
|
945 kumpf 1.92 PEGASUS_NAMESPACE_END
|