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