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