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