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