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