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