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