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