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 karl 1.91 #include "Tracer.h"
|
44 kumpf 1.93 #include <Pegasus/Common/MessageLoader.h>
|
45 karl 1.91
46 #ifdef PEGASUS_PLATFORM_OS400_ISERIES_IBM
47 #include "EBCDIC_OS400.h"
48 #endif
49
50
51 PEGASUS_USING_STD;
52
53 PEGASUS_NAMESPACE_BEGIN
54
55
56 static int MAX_CONNECTION_QUEUE_LENGTH = -1;
57
58 ////////////////////////////////////////////////////////////////////////////////
59 //
60 // HTTPAcceptorRep
61 //
62 ////////////////////////////////////////////////////////////////////////////////
63
64 class HTTPAcceptorRep
65 {
66 karl 1.91 public:
67 HTTPAcceptorRep(Boolean local)
68 {
69 if (local)
70 {
71 #ifndef PEGASUS_DISABLE_LOCAL_DOMAIN_SOCKET
|
72 kumpf 1.92 address =
73 reinterpret_cast<struct sockaddr*>(new struct sockaddr_un);
|
74 karl 1.91 address_size = sizeof(struct sockaddr_un);
75 #else
76 PEGASUS_ASSERT(false);
77 #endif
78 }
79 else
80 {
|
81 kumpf 1.92 address =
82 reinterpret_cast<struct sockaddr*>(new struct sockaddr_in);
|
83 karl 1.91 address_size = sizeof(struct sockaddr_in);
84 }
85 }
86 ~HTTPAcceptorRep()
87 {
88 delete address;
89 }
90 struct sockaddr* address;
91
92 SocketLength address_size;
93 Mutex _connection_mut;
94
95 SocketHandle socket;
96 Array<HTTPConnection*> connections;
97 };
98
99
100 ////////////////////////////////////////////////////////////////////////////////
101 //
102 // HTTPAcceptor
103 //
104 karl 1.91 ////////////////////////////////////////////////////////////////////////////////
105
106 HTTPAcceptor::HTTPAcceptor(Monitor* monitor,
107 MessageQueue* outputMessageQueue,
108 Boolean localConnection,
109 Uint32 portNumber,
110 SSLContext * sslcontext,
111 ReadWriteSem* sslContextObjectLock)
112 : Base(PEGASUS_QUEUENAME_HTTPACCEPTOR), // ATTN: Need unique names?
113 _monitor(monitor),
114 _outputMessageQueue(outputMessageQueue),
115 _rep(0),
116 _entry_index(-1),
117 _localConnection(localConnection),
118 _portNumber(portNumber),
119 _sslcontext(sslcontext),
120 _sslContextObjectLock(sslContextObjectLock)
121 {
122 Socket::initializeInterface();
123
124 /*
|
125 kumpf 1.92 Platforms interpret the value of MAX_CONNECTION_QUEUE_LENGTH
126 differently. Some platforms interpret the value literally, while
127 others multiply a fudge factor. When the server is under stress from
128 multiple clients with multiple requests, toggling this number may
129 prevent clients from being dropped. Instead of hard coding the
130 value, we allow an environment variable to be set which specifies a
131 number greater than the maximum concurrent client connections
132 possible. If this environment var is not specified, then
133 MAX_CONNECTION_QUEUE_LENGTH = 15.
|
134 karl 1.91 */
135
|
136 kumpf 1.92 //To engage runtime backlog queue length: uncomment the following block AND
137 //comment out the line MAX_CONNECTION_QUEUE_LENGTH = 15
|
138 karl 1.91
139 /*
|
140 kumpf 1.92 if (MAX_CONNECTION_QUEUE_LENGTH == -1)
141 {
|
142 karl 1.91 #ifdef PEGASUS_PLATFORM_OS400_ISERIES_IBM
143 #pragma convert(37)
|
144 kumpf 1.92 const char* env = getenv("PEGASUS_MAX_BACKLOG_CONNECTION_QUEUE");
145 EtoA(env);
|
146 karl 1.91 #pragma convert(0)
147 #else
|
148 kumpf 1.92 const char* env = getenv("PEGASUS_MAX_BACKLOG_CONNECTION_QUEUE");
|
149 karl 1.91 #endif
|
150 kumpf 1.92 if (!env)
151 {
|
152 karl 1.91 MAX_CONNECTION_QUEUE_LENGTH = 15;
|
153 kumpf 1.92 }
154 else
155 {
156 char* end = NULL;
157 MAX_CONNECTION_QUEUE_LENGTH = strtol(env, &end, 10);
158 if (*end)
159 MAX_CONNECTION_QUEUE_LENGTH = 15;
160 cout << " MAX_CONNECTION_QUEUE_LENGTH = " <<
161 MAX_CONNECTION_QUEUE_LENGTH << endl;
162 }
|
163 karl 1.91 }
164 */
|
165 kumpf 1.92 MAX_CONNECTION_QUEUE_LENGTH = 15;
|
166 karl 1.91 }
167
168 HTTPAcceptor::~HTTPAcceptor()
169 {
|
170 kumpf 1.92 destroyConnections();
171 unbind();
172 // ATTN: Is this correct in a multi-HTTPAcceptor server?
173 Socket::uninitializeInterface();
|
174 karl 1.91 }
175
176 void HTTPAcceptor::handleEnqueue(Message *message)
177 {
|
178 kumpf 1.92 if (!message)
179 return;
180
181 PEGASUS_ASSERT(_rep != 0);
182 switch (message->getType())
183 {
184 case SOCKET_MESSAGE:
185 {
186 SocketMessage* socketMessage = (SocketMessage*)message;
187
188 // If this is a connection request:
189
190 if (socketMessage->socket == _rep->socket &&
191 socketMessage->events & SocketMessage::READ)
192 {
193 _acceptConnection();
194 }
195 else
196 {
197 // ATTN! this can't happen!
|
198 marek 1.95 PEG_TRACE_CSTRING(TRC_DISCARDED_DATA, Tracer::LEVEL2,
|
199 kumpf 1.92 "HTTPAcceptor::handleEnqueue: Invalid SOCKET_MESSAGE "
200 "received.");
201 }
|
202 karl 1.91
203 break;
|
204 kumpf 1.92 }
205
206 case CLOSE_CONNECTION_MESSAGE:
207 {
208 CloseConnectionMessage* closeConnectionMessage =
209 (CloseConnectionMessage*)message;
210
211 AutoMutex autoMut(_rep->_connection_mut);
212
213 for (Uint32 i = 0, n = _rep->connections.size(); i < n; i++)
214 {
215 HTTPConnection* connection = _rep->connections[i];
216 SocketHandle socket = connection->getSocket();
217
218 if (socket == closeConnectionMessage->socket)
219 {
220 _monitor->unsolicitSocketMessages(socket);
221 _rep->connections.remove(i);
222 delete connection;
223 break;
224 }
225 kumpf 1.92 }
|
226 karl 1.91
|
227 kumpf 1.92 break;
228 }
|
229 karl 1.91
|
230 kumpf 1.92 default:
231 // ATTN: need unexpected message error!
|
232 marek 1.95 PEG_TRACE_CSTRING(TRC_DISCARDED_DATA, Tracer::LEVEL2,
|
233 kumpf 1.92 "HTTPAcceptor::handleEnqueue: Invalid MESSAGE received.");
234 break;
235 }
|
236 karl 1.91
|
237 kumpf 1.92 delete message;
|
238 karl 1.91 }
239
240
241 void HTTPAcceptor::handleEnqueue()
242 {
|
243 kumpf 1.92 Message* message = dequeue();
|
244 karl 1.91
|
245 kumpf 1.92 if (!message)
246 {
|
247 marek 1.95 PEG_TRACE_CSTRING(TRC_DISCARDED_DATA, Tracer::LEVEL2,
|
248 kumpf 1.92 "HTTPAcceptor::handleEnqueue(): No message on queue.");
249 return;
250 }
|
251 karl 1.91
|
252 kumpf 1.92 handleEnqueue(message);
|
253 karl 1.91 }
254
255 void HTTPAcceptor::bind()
256 {
|
257 kumpf 1.92 if (_rep)
258 {
259 MessageLoaderParms parms("Common.HTTPAcceptor.ALREADY_BOUND",
260 "HTTPAcceptor already bound");
|
261 karl 1.91
|
262 marek 1.95 PEG_TRACE_CSTRING(TRC_DISCARDED_DATA, Tracer::LEVEL2,
|
263 kumpf 1.92 "HTTPAcceptor::bind: HTTPAcceptor already bound.");
264 throw BindFailedException(parms);
265 }
|
266 karl 1.91
|
267 kumpf 1.92 _rep = new HTTPAcceptorRep(_localConnection);
|
268 karl 1.91
|
269 kumpf 1.92 // bind address
270 _bind();
|
271 karl 1.91 }
272
273 /**
|
274 kumpf 1.92 _bind - creates a new server socket and bind socket to the port address.
275 If PEGASUS_DISABLE_LOCAL_DOMAIN_SOCKET is not defined, the port number is
276 ignored and a domain socket is bound.
|
277 karl 1.91 */
278 void HTTPAcceptor::_bind()
279 {
|
280 kumpf 1.92 PEGASUS_ASSERT(_rep != 0);
281 // Create address:
|
282 karl 1.91
|
283 kumpf 1.92 memset(_rep->address, 0, sizeof(*_rep->address));
|
284 karl 1.91
|
285 kumpf 1.92 if (_localConnection)
286 {
|
287 karl 1.91 #ifndef PEGASUS_DISABLE_LOCAL_DOMAIN_SOCKET
|
288 kumpf 1.92 reinterpret_cast<struct sockaddr_un*>(_rep->address)->sun_family =
289 AF_UNIX;
290 strcpy(reinterpret_cast<struct sockaddr_un*>(_rep->address)->sun_path,
291 PEGASUS_LOCAL_DOMAIN_SOCKET_PATH);
|
292 karl 1.91 #ifdef PEGASUS_PLATFORM_OS400_ISERIES_IBM
|
293 kumpf 1.92 AtoE(reinterpret_cast<struct sockaddr_un*>(_rep->address)->sun_path);
|
294 karl 1.91 #endif
|
295 kumpf 1.92 ::unlink(
296 reinterpret_cast<struct sockaddr_un*>(_rep->address)->sun_path);
|
297 karl 1.91 #else
|
298 kumpf 1.92 PEGASUS_ASSERT(false);
|
299 karl 1.91 #endif
|
300 kumpf 1.92 }
301 else
302 {
303 reinterpret_cast<struct sockaddr_in*>(_rep->address)->sin_addr.s_addr =
304 INADDR_ANY;
305 reinterpret_cast<struct sockaddr_in*>(_rep->address)->sin_family =
306 AF_INET;
307 reinterpret_cast<struct sockaddr_in*>(_rep->address)->sin_port =
308 htons(_portNumber);
309 }
310
311 // Create socket:
312
313 if (_localConnection)
314 {
315 _rep->socket = Socket::createSocket(AF_UNIX, SOCK_STREAM, 0);
316 }
317 else
318 {
319 _rep->socket = Socket::createSocket(PF_INET, SOCK_STREAM, IPPROTO_TCP);
320 }
321 kumpf 1.92
322 if (_rep->socket < 0)
323 {
324 delete _rep;
325 _rep = 0;
326 MessageLoaderParms parms("Common.HTTPAcceptor.FAILED_CREATE_SOCKET",
327 "Failed to create socket");
|
328 marek 1.95 PEG_TRACE_CSTRING(TRC_DISCARDED_DATA, Tracer::LEVEL2,
|
329 kumpf 1.92 "HTTPAcceptor::_bind _rep->socket < 0");
330 throw BindFailedException(parms);
331 }
|
332 karl 1.91
333
334 // set the close-on-exec bit for this file handle.
335 // any unix that forks needs this bit set.
336 #if !defined PEGASUS_OS_TYPE_WINDOWS && !defined(PEGASUS_OS_VMS)
|
337 kumpf 1.92 int sock_flags;
338 if ((sock_flags = fcntl(_rep->socket, F_GETFD, 0)) < 0)
339 {
|
340 marek 1.95 PEG_TRACE_CSTRING(TRC_DISCARDED_DATA, Tracer::LEVEL2,
|
341 kumpf 1.92 "HTTPAcceptor::_bind: fcntl(F_GETFD) failed");
342 }
343 else
344 {
345 sock_flags |= FD_CLOEXEC;
346 if (fcntl(_rep->socket, F_SETFD, sock_flags) < 0)
347 {
|
348 marek 1.95 PEG_TRACE_CSTRING(TRC_DISCARDED_DATA, Tracer::LEVEL2,
|
349 kumpf 1.92 "HTTPAcceptor::_bind: fcntl(F_SETFD) failed");
350 }
351 }
352 #endif
353
354
355 //
356 // Set the socket option SO_REUSEADDR to reuse the socket address so
357 // that we can rebind to a new socket using the same address when we
358 // need to resume the cimom as a result of a timeout during a Shutdown
359 // operation.
360 //
361 int opt=1;
362 if (setsockopt(_rep->socket, SOL_SOCKET, SO_REUSEADDR,
363 (char *)&opt, sizeof(opt)) < 0)
364 {
365 Socket::close(_rep->socket);
366 delete _rep;
367 _rep = 0;
368 MessageLoaderParms parms("Common.HTTPAcceptor.FAILED_SET_SOCKET_OPTION",
369 "Failed to set socket option");
|
370 marek 1.95 PEG_TRACE_CSTRING(TRC_DISCARDED_DATA, Tracer::LEVEL2,
|
371 kumpf 1.92 "HTTPAcceptor::_bind: Failed to set socket option.");
372 throw BindFailedException(parms);
373 }
374
375
376 //
377 // Bind socket to port:
378 //
379 if (::bind(_rep->socket, _rep->address, _rep->address_size) < 0)
380 {
381 Socket::close(_rep->socket);
382 delete _rep;
383 _rep = 0;
384 MessageLoaderParms parms("Common.HTTPAcceptor.FAILED_BIND_SOCKET",
385 "Failed to bind socket");
|
386 marek 1.95 PEG_TRACE_CSTRING(TRC_DISCARDED_DATA, Tracer::LEVEL2,
|
387 kumpf 1.92 "HTTPAcceptor::_bind: Failed to bind socket.");
388 throw BindFailedException(parms);
389 }
390
391
392 //
393 // Get the actual port value used if the caller specified a port value of 0.
394 //
395 if (_portNumber == 0)
396 {
397 sockaddr_in buf;
398 SocketLength bufSize = sizeof(buf);
399 if (getsockname(_rep->socket, reinterpret_cast<sockaddr *>(&buf),
400 &bufSize) == 0 )
401 {
402 _portNumber = ntohs(buf.sin_port);
403 }
404 }
405
406
407 //
408 kumpf 1.92 // Change permissions on Linux local domain socket to allow writes by
409 // others.
410 //
|
411 karl 1.91 #if !defined(PEGASUS_DISABLE_LOCAL_DOMAIN_SOCKET) && \
|
412 kumpf 1.92 (defined(PEGASUS_PLATFORM_LINUX_GENERIC_GNU) || \
413 defined(PEGASUS_PLATFORM_ZOS_ZSERIES_IBM))
414 if (_localConnection)
415 {
416 if (::chmod(PEGASUS_LOCAL_DOMAIN_SOCKET_PATH,
417 S_IRUSR | S_IWUSR | S_IXUSR |
418 S_IRGRP | S_IWGRP | S_IXGRP |
419 S_IROTH | S_IWOTH | S_IXOTH ) < 0 )
420 {
421 Socket::close(_rep->socket);
422 delete _rep;
423 _rep = 0;
424 MessageLoaderParms parms("Common.HTTPAcceptor.FAILED_BIND_SOCKET",
425 "Failed to bind socket");
|
426 marek 1.95 PEG_TRACE_CSTRING(TRC_DISCARDED_DATA, Tracer::LEVEL2,
|
427 kumpf 1.92 "HTTPAcceptor::_bind: Failed to set domain socket "
428 "permissions.");
429 throw BindFailedException(parms);
430 }
431 }
432 #endif
433
434 // Set up listening on the given socket:
435
436 //int const MAX_CONNECTION_QUEUE_LENGTH = 15;
437
438 if (listen(_rep->socket, MAX_CONNECTION_QUEUE_LENGTH) < 0)
439 {
440 Socket::close(_rep->socket);
441 delete _rep;
442 _rep = 0;
443 MessageLoaderParms parms("Common.HTTPAcceptor.FAILED_BIND_SOCKET",
444 "Failed to bind socket");
|
445 marek 1.95 PEG_TRACE_CSTRING(TRC_DISCARDED_DATA, Tracer::LEVEL2,
|
446 kumpf 1.92 "HTTPAcceptor::_bind: Failed to bind socket(1).");
447 throw BindFailedException(parms);
448 }
449
450 // Register to receive SocketMessages on this socket:
451
452 if (-1 == ( _entry_index = _monitor->solicitSocketMessages(
453 _rep->socket,
454 SocketMessage::READ | SocketMessage::EXCEPTION,
455 getQueueId(),
456 Monitor::ACCEPTOR)))
457 {
458 Socket::close(_rep->socket);
459 delete _rep;
460 _rep = 0;
461 MessageLoaderParms parms(
462 "Common.HTTPAcceptor.FAILED_SOLICIT_SOCKET_MESSAGES",
463 "Failed to solicit socket messaeges");
|
464 marek 1.95 PEG_TRACE_CSTRING(TRC_DISCARDED_DATA, Tracer::LEVEL2,
|
465 kumpf 1.92 "HTTPAcceptor::_bind: Failed to solicit socket messages(2).");
466 throw BindFailedException(parms);
467 }
|
468 karl 1.91 }
469
470 /**
|
471 kumpf 1.92 closeConnectionSocket - close the server listening socket to disallow
472 new client connections.
|
473 karl 1.91 */
474 void HTTPAcceptor::closeConnectionSocket()
475 {
|
476 kumpf 1.92 if (_rep)
477 {
478 // unregister the socket
479
480 // ATTN - comment out - see CIMServer::stopClientConnection()
481 //_monitor->unsolicitSocketMessages(_rep->socket);
482
483 // close the socket
484 Socket::close(_rep->socket);
485 // Unlink Local Domain Socket Bug# 3312
486 if (_localConnection)
487 {
|
488 karl 1.91 #ifndef PEGASUS_DISABLE_LOCAL_DOMAIN_SOCKET
|
489 marek 1.95 PEG_TRACE_CSTRING(TRC_HTTP, Tracer::LEVEL2,
|
490 kumpf 1.92 "HTTPAcceptor::closeConnectionSocket Unlinking local "
491 "connection.");
492 ::unlink(
493 reinterpret_cast<struct sockaddr_un*>(_rep->address)->sun_path);
|
494 karl 1.91 #else
|
495 kumpf 1.92 PEGASUS_ASSERT(false);
|
496 karl 1.91 #endif
|
497 kumpf 1.92 }
498 }
499 else
500 {
|
501 marek 1.95 PEG_TRACE_CSTRING(TRC_DISCARDED_DATA, Tracer::LEVEL2,
|
502 kumpf 1.92 "HTTPAcceptor::closeConnectionSocket failure _rep is null.");
503 }
|
504 karl 1.91 }
505
506 /**
507 reopenConnectionSocket - creates a new server socket.
508 */
509 void HTTPAcceptor::reopenConnectionSocket()
510 {
|
511 kumpf 1.92 if (_rep)
512 {
513 _bind();
514 }
515 else
516 {
|
517 marek 1.95 PEG_TRACE_CSTRING(TRC_DISCARDED_DATA, Tracer::LEVEL2,
|
518 kumpf 1.92 "HTTPAcceptor::reopenConnectionSocket failure _rep is null.");
519 }
|
520 karl 1.91 }
521
522
523 /**
524 reconnectConnectionSocket - creates a new server socket.
525 */
526 void HTTPAcceptor::reconnectConnectionSocket()
527 {
|
528 kumpf 1.92 if (_rep)
529 {
530 // unregister the socket
531 _monitor->unsolicitSocketMessages(_rep->socket);
532 // close the socket
533 Socket::close(_rep->socket);
534 // Unlink Local Domain Socket Bug# 3312
535 if (_localConnection)
536 {
|
537 karl 1.91 #ifndef PEGASUS_DISABLE_LOCAL_DOMAIN_SOCKET
|
538 marek 1.95 PEG_TRACE_CSTRING(TRC_HTTP, Tracer::LEVEL2,
|
539 kumpf 1.92 "HTTPAcceptor::reconnectConnectionSocket Unlinking local "
540 "connection." );
541 ::unlink(
542 reinterpret_cast<struct sockaddr_un*>(_rep->address)->sun_path);
|
543 karl 1.91 #else
|
544 kumpf 1.92 PEGASUS_ASSERT(false);
|
545 karl 1.91 #endif
|
546 kumpf 1.92 }
547 // open the socket
548 _bind();
549 }
550 else
551 {
|
552 marek 1.95 PEG_TRACE_CSTRING(TRC_DISCARDED_DATA, Tracer::LEVEL2,
|
553 kumpf 1.92 "HTTPAcceptor::reconnectConnectionSocket failure _rep is null.");
554 }
|
555 karl 1.91 }
556
557 /**
|
558 kumpf 1.92 getOutstandingRequestCount - returns the number of outstanding requests.
|
559 karl 1.91 */
560 Uint32 HTTPAcceptor::getOutstandingRequestCount() const
561 {
|
562 kumpf 1.92 Uint32 count = 0;
563 if (_rep)
564 {
565 AutoMutex autoMut(_rep->_connection_mut);
566 if (_rep->connections.size() > 0)
567 {
568 HTTPConnection* connection = _rep->connections[0];
569 count = connection->getRequestCount();
570 }
571 }
572 return count;
|
573 karl 1.91 }
574
575
576 /**
577 getPortNumber - returns the port number used for the connection
578 */
579 Uint32 HTTPAcceptor::getPortNumber() const
580 {
581 return _portNumber;
582 }
583
584 void HTTPAcceptor::setSocketWriteTimeout(Uint32 socketWriteTimeout)
585 {
586 _socketWriteTimeout = socketWriteTimeout;
587 }
588
589 void HTTPAcceptor::unbind()
590 {
|
591 kumpf 1.92 if (_rep)
592 {
593 _portNumber = 0;
594 Socket::close(_rep->socket);
|
595 karl 1.91
|
596 kumpf 1.92 if (_localConnection)
597 {
|
598 karl 1.91 #ifndef PEGASUS_DISABLE_LOCAL_DOMAIN_SOCKET
|
599 kumpf 1.92 ::unlink(
600 reinterpret_cast<struct sockaddr_un*>(_rep->address)->sun_path);
|
601 karl 1.91 #else
|
602 kumpf 1.92 PEGASUS_ASSERT(false);
|
603 karl 1.91 #endif
|
604 kumpf 1.92 }
|
605 karl 1.91
|
606 kumpf 1.92 delete _rep;
607 _rep = 0;
608 }
609 else
610 {
|
611 marek 1.95 PEG_TRACE_CSTRING(TRC_DISCARDED_DATA, Tracer::LEVEL2,
|
612 kumpf 1.92 "HTTPAcceptor::unbind failure _rep is null." );
613 }
|
614 karl 1.91 }
615
616 void HTTPAcceptor::destroyConnections()
617 {
|
618 kumpf 1.92 if (_rep)
619 {
620 // For each connection created by this object:
|
621 karl 1.91
|
622 kumpf 1.92 AutoMutex autoMut(_rep->_connection_mut);
623 for (Uint32 i = 0, n = _rep->connections.size(); i < n; i++)
624 {
625 HTTPConnection* connection = _rep->connections[i];
626 SocketHandle socket = connection->getSocket();
|
627 karl 1.91
|
628 kumpf 1.92 // Unsolicit SocketMessages:
|
629 karl 1.91
|
630 kumpf 1.92 _monitor->unsolicitSocketMessages(socket);
|
631 karl 1.91
|
632 kumpf 1.92 // Destroy the connection (causing it to close):
|
633 karl 1.91
|
634 kumpf 1.92 while (connection->refcount.get()) { }
635 delete connection;
636 }
|
637 karl 1.91
|
638 kumpf 1.92 _rep->connections.clear();
639 }
|
640 karl 1.91 }
641
642 void HTTPAcceptor::_acceptConnection()
643 {
|
644 kumpf 1.92 // This function cannot be called on an invalid socket!
|
645 karl 1.91
|
646 kumpf 1.92 PEGASUS_ASSERT(_rep != 0);
|
647 karl 1.91
|
648 kumpf 1.92 // Accept the connection (populate the address):
|
649 karl 1.91
|
650 kumpf 1.92 struct sockaddr* accept_address;
651 SocketLength address_size;
|
652 karl 1.91
|
653 kumpf 1.92 if (_localConnection)
654 {
|
655 karl 1.91 #ifndef PEGASUS_DISABLE_LOCAL_DOMAIN_SOCKET
|
656 kumpf 1.92 accept_address =
657 reinterpret_cast<struct sockaddr*>(new struct sockaddr_un);
658 address_size = sizeof(struct sockaddr_un);
|
659 karl 1.91 #else
|
660 kumpf 1.92 PEGASUS_ASSERT(false);
|
661 karl 1.91 #endif
|
662 kumpf 1.92 }
663 else
664 {
665 accept_address =
666 reinterpret_cast<struct sockaddr*>(new struct sockaddr_in);
667 address_size = sizeof(struct sockaddr_in);
668 }
669
|
670 dave.sudlik 1.94 SocketHandle socket;
671 #ifdef PEGASUS_OS_TYPE_WINDOWS
672 socket = accept(_rep->socket, accept_address, &address_size);
673 #else
674 while (
675 ((socket = accept(_rep->socket, accept_address, &address_size)) == -1)
676 && (errno == EINTR))
677 ;
678 #endif
|
679 kumpf 1.92
680 if (socket == PEGASUS_SOCKET_ERROR)
681 {
682 // the remote connection is invalid, destroy client address.
683 delete accept_address;
684
685 // TCPIP is down reconnect this acceptor
686 if (getSocketError() == PEGASUS_NETWORK_TCPIP_STOPPED)
687 {
|
688 marek 1.95 PEG_TRACE_CSTRING(TRC_DISCARDED_DATA, Tracer::LEVEL2,
|
689 kumpf 1.92 "Socket has an IO error. TCP/IP down. Try to reconnect.");
690
691 reconnectConnectionSocket();
692
693 return;
694 }
|
695 karl 1.91
|
696 kumpf 1.92 Logger::put(Logger::STANDARD_LOG, System::CIMSERVER, Logger::TRACE,
697 "HTTPAcceptor - accept() failure. errno: $0", errno);
|
698 karl 1.91
|
699 marek 1.95 PEG_TRACE_CSTRING(TRC_DISCARDED_DATA, Tracer::LEVEL2,
|
700 kumpf 1.92 "HTTPAcceptor: accept() failed");
701 return;
702 }
|
703 karl 1.91
|
704 kumpf 1.92 String ipAddress;
|
705 karl 1.91
|
706 kumpf 1.92 if (_localConnection)
707 {
708 ipAddress = "localhost";
709 }
710 else
711 {
712 unsigned char* sa = reinterpret_cast<unsigned char*>(
713 &reinterpret_cast<struct sockaddr_in*>(
714 accept_address)->sin_addr.s_addr);
715 char ipBuffer[32];
716 sprintf(ipBuffer, "%u.%u.%u.%u", sa[0], sa[1], sa[2], sa[3]);
717 ipAddress = ipBuffer;
718 }
|
719 karl 1.91
|
720 kumpf 1.92 delete accept_address;
|
721 karl 1.91
722 // set the close on exec flag
723 #if !defined(PEGASUS_OS_TYPE_WINDOWS) && !defined(PEGASUS_OS_VMS)
|
724 kumpf 1.92 int sock_flags;
725 if ((sock_flags = fcntl(socket, F_GETFD, 0)) < 0)
726 {
|
727 marek 1.95 PEG_TRACE_CSTRING(TRC_DISCARDED_DATA, Tracer::LEVEL2,
|
728 kumpf 1.92 "HTTPAcceptor: fcntl(F_GETFD) failed");
729 }
730 else
731 {
732 sock_flags |= FD_CLOEXEC;
733 if (fcntl(socket, F_SETFD, sock_flags) < 0)
734 {
|
735 marek 1.95 PEG_TRACE_CSTRING(TRC_DISCARDED_DATA, Tracer::LEVEL2,
|
736 kumpf 1.92 "HTTPAcceptor: fcntl(F_SETFD) failed");
737 }
738 }
|
739 karl 1.91 #endif
740
741
|
742 kumpf 1.92 PEG_LOGGER_TRACE((Logger::STANDARD_LOG, System::CIMSERVER, 0,
743 "HTTPAcceptor - accept() success. Socket: $1" ,socket));
744
|
745 kumpf 1.96 SharedPtr<MP_Socket> mp_socket(new MP_Socket(
|
746 sushma.fernandes 1.97 socket, _sslcontext, _sslContextObjectLock, ipAddress));
|
747 kumpf 1.92
748 mp_socket->setSocketWriteTimeout(_socketWriteTimeout);
749
750 // Perform the SSL handshake, if applicable. Make the socket non-blocking
751 // for this operation so we can send it back to the Monitor's select() loop
752 // if it takes a while.
753
754 mp_socket->disableBlocking();
755 Sint32 socketAcceptStatus = mp_socket->accept();
756 mp_socket->enableBlocking();
757
758 if (socketAcceptStatus < 0)
759 {
|
760 marek 1.95 PEG_TRACE_CSTRING(TRC_DISCARDED_DATA, Tracer::LEVEL2,
|
761 kumpf 1.92 "HTTPAcceptor: SSL_accept() failed");
762 mp_socket->close();
763 return;
764 }
765
766 // Create a new connection and add it to the connection list:
767
768 HTTPConnection* connection = new HTTPConnection(_monitor, mp_socket,
769 ipAddress, this, static_cast<MessageQueue *>(_outputMessageQueue));
770
771 if (socketAcceptStatus == 0)
772 {
|
773 marek 1.95 PEG_TRACE_CSTRING(TRC_HTTP, Tracer::LEVEL2,
|
774 kumpf 1.92 "HTTPAcceptor: SSL_accept() pending");
775 connection->_acceptPending = true;
776 }
|
777 karl 1.91
|
778 kumpf 1.92 // Solicit events on this new connection's socket:
779 int index;
|
780 karl 1.91
|
781 kumpf 1.92 if (-1 == (index = _monitor->solicitSocketMessages(
782 connection->getSocket(),
783 SocketMessage::READ | SocketMessage::EXCEPTION,
784 connection->getQueueId(), Monitor::CONNECTION)) )
785 {
786 // ATTN-DE-P2-2003100503::TODO::Need to enhance code to return
787 // an error message to Client application.
|
788 marek 1.95 PEG_TRACE_CSTRING(TRC_DISCARDED_DATA, Tracer::LEVEL2,
|
789 kumpf 1.92 "HTTPAcceptor::_acceptConnection: Attempt to allocate entry in "
790 "_entries table failed.");
791 delete connection;
792 Socket::close(socket);
793 return;
794 }
|
795 karl 1.91
|
796 kumpf 1.92 // Save the socket for cleanup later:
797 connection->_entry_index = index;
798 AutoMutex autoMut(_rep->_connection_mut);
799 _rep->connections.append(connection);
|
800 karl 1.91 }
801
|
802 kumpf 1.92 PEGASUS_NAMESPACE_END
|