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 // Author: Mike Brasher (mbrasher@bmc.com)
33 //
34 // Modified By:
|
35 david.dillard 1.64 // Jenny Yu, Hewlett-Packard Company (jenny_yu@hp.com)
36 // Nag Boranna, Hewlett-Packard Company (nagaraja_boranna@hp.com)
37 // Dave Rosckes (rosckes@us.ibm.com)
38 // Denise Eckstein (denise.eckstein@hp.com)
39 // Alagaraja Ramasubramanian (alags_raj@in.ibm.com) for Bug#1090
40 // Amit Arora, IBM (amita@in.ibm.com) for Bug#2541
41 // Roger Kumpf, Hewlett-Packard Company (roger_kumpf@hp.com)
42 // Sean Keenan, Hewlett-Packard Company (sean.keenan@hp.com)
43 // Josephine Eskaline Joyce, IBM (jojustin@in.ibm.com) for Bug#2065
|
44 david.dillard 1.74 // David Dillard, Symantec Corp. (david_dillard@symantec.com)
|
45 j.alex 1.67 // John Alex, IBM (johnalex@us.ibm.com) for Bug#3312
|
46 mike 1.2 //
47 //%/////////////////////////////////////////////////////////////////////////////
48
49 #include "Config.h"
|
50 kumpf 1.15 #include "Constants.h"
|
51 mike 1.2 #include <iostream>
|
52 w.white 1.81.8.1 #include "Socket.h"
|
53 mike 1.2
|
54 david.dillard 1.78 #ifdef PEGASUS_OS_TYPE_WINDOWS
|
55 mday 1.12 #include <windows.h>
|
56 mike 1.2 #else
57 # include <cctype>
58 # include <cstdlib>
59 # include <errno.h>
60 # include <fcntl.h>
61 # include <netdb.h>
62 # include <netinet/in.h>
|
63 mike 1.79 # include <netinet/tcp.h>
|
64 mike 1.2 # include <arpa/inet.h>
65 # include <sys/socket.h>
|
66 h.sterling 1.63 # ifndef PEGASUS_DISABLE_LOCAL_DOMAIN_SOCKET
|
67 kumpf 1.26 # include <unistd.h>
|
68 kumpf 1.11 # include <sys/un.h>
69 # endif
|
70 mike 1.2 #endif
71
72 #include "Socket.h"
73 #include "TLS.h"
74 #include "HTTPAcceptor.h"
75 #include "HTTPConnection.h"
|
76 kumpf 1.19 #include "Tracer.h"
|
77 humberto 1.30 #include <Pegasus/Common/MessageLoader.h> //l10n
|
78 mike 1.2
|
79 chuck 1.38 #ifdef PEGASUS_PLATFORM_OS400_ISERIES_IBM
80 #include "OS400ConvertChar.h"
81 #endif
82
|
83 mike 1.79
|
84 mike 1.2 PEGASUS_USING_STD;
85
86 PEGASUS_NAMESPACE_BEGIN
87
|
88 david.dillard 1.65
|
89 a.arora 1.51 static int MAX_CONNECTION_QUEUE_LENGTH = -1;
90
|
91 mike 1.2 ////////////////////////////////////////////////////////////////////////////////
92 //
93 // HTTPAcceptorRep
94 //
95 ////////////////////////////////////////////////////////////////////////////////
96
|
97 kumpf 1.25 class HTTPAcceptorRep
|
98 mike 1.2 {
|
99 kumpf 1.25 public:
100 HTTPAcceptorRep(Boolean local)
101 {
102 if (local)
103 {
|
104 j.alex 1.81.8.2 #ifndef PEGASUS_OS_TYPE_WINDOWS
|
105 h.sterling 1.63 #ifndef PEGASUS_DISABLE_LOCAL_DOMAIN_SOCKET
|
106 j.alex 1.81.8.2
|
107 kumpf 1.25 address = reinterpret_cast<struct sockaddr*>(new struct sockaddr_un);
108 address_size = sizeof(struct sockaddr_un);
|
109 kumpf 1.11 #else
|
110 kumpf 1.25 PEGASUS_ASSERT(false);
|
111 kumpf 1.11 #endif
|
112 j.alex 1.81.8.2
113 #endif
|
114 david.dillard 1.64 }
|
115 kumpf 1.25 else
116 {
117 address = reinterpret_cast<struct sockaddr*>(new struct sockaddr_in);
118 address_size = sizeof(struct sockaddr_in);
119 }
120 }
|
121 konrad.r 1.69 ~HTTPAcceptorRep()
122 {
|
123 david.dillard 1.73 delete address;
|
124 konrad.r 1.69 }
|
125 kumpf 1.25 struct sockaddr* address;
126
|
127 mike 1.77 PEGASUS_SOCKLEN_T address_size;
128 Mutex _connection_mut;
|
129 david.dillard 1.64
|
130 mike 1.77 PEGASUS_SOCKET socket;
|
131 j.alex 1.81.8.2 #ifdef PEGASUS_OS_TYPE_WINDOWS
132 NamedPipeServer* namedPipeServer;
133 #endif
|
134 w.white 1.81.8.1 Array<HTTPConnection*> connections;
|
135 j.alex 1.81.8.2 /*
136 #ifdef PEGASUS_OS_TYPE_WINDOWS
137 // This method creates and connects to a named pipe
138 void createNamedPipe();
139 NamedPipeServer* namedPipeServer;
140 void _acceptNamedPipeConnection(NamedPipeMessage* namedPipeMessage);
141 #endif
142 */
|
143 w.white 1.81.8.1
144
|
145 mike 1.2 };
146
|
147 mike 1.79 //------------------------------------------------------------------------------
148 //
149 // _setTCPNoDelay()
150 //
151 //------------------------------------------------------------------------------
152
153 inline void _setTCPNoDelay(PEGASUS_SOCKET socket)
154 {
155 // This function disables "Nagle's Algorithm" also known as "the TCP delay
156 // algorithm", which causes read operations to obtain whatever data is
157 // already in the input queue and then wait a little longer to see if
158 // more data arrives. This algorithm optimizes the case in which data is
159 // sent in only one direction but severely impairs performance of round
160 // trip servers. Disabling TCP delay is a standard technique for round
161 // trip servers.
162
163 int opt = 1;
164 setsockopt(socket, IPPROTO_TCP, TCP_NODELAY, (char*)&opt, sizeof(opt));
165 }
166
|
167 mike 1.2 ////////////////////////////////////////////////////////////////////////////////
168 //
169 // HTTPAcceptor
170 //
171 ////////////////////////////////////////////////////////////////////////////////
172
|
173 kumpf 1.25 HTTPAcceptor::HTTPAcceptor(Monitor* monitor,
174 MessageQueue* outputMessageQueue,
175 Boolean localConnection,
176 Uint32 portNumber,
|
177 kumpf 1.49 SSLContext * sslcontext,
|
178 nag.boranna 1.59 Boolean exportConnection,
179 ReadWriteSem* sslContextObjectLock)
|
180 kumpf 1.25 : Base(PEGASUS_QUEUENAME_HTTPACCEPTOR), // ATTN: Need unique names?
181 _monitor(monitor),
182 _outputMessageQueue(outputMessageQueue),
183 _rep(0),
184 _entry_index(-1),
185 _localConnection(localConnection),
186 _portNumber(portNumber),
|
187 kumpf 1.49 _sslcontext(sslcontext),
|
188 nag.boranna 1.59 _exportConnection(exportConnection),
189 _sslContextObjectLock(sslContextObjectLock)
|
190 mike 1.2 {
|
191 mday 1.7 Socket::initializeInterface();
|
192 david.dillard 1.64
|
193 a.arora 1.51 /*
194 Platforms interpret the value of MAX_CONNECTION_QUEUE_LENGTH differently. Some platforms interpret
195 the value literally, while others multiply a fudge factor. When the server is under
196 stress from multiple clients with multiple requests, toggling this number may prevent clients from
197 being dropped. Instead of hard coding the value, we allow an environment variable to be set which
198 specifies a number greater than the maximum concurrent client connections possible. If this environment
199 var is not specified, then MAX_CONNECTION_QUEUE_LENGTH = 15.
200 */
201
202 //To engage runtime backlog queue length: uncomment the following block AND comment out the line MAX_CONNECTION_QUEUE_LENGTH = 15
203
204 /*
205 if(MAX_CONNECTION_QUEUE_LENGTH == -1){
206 #ifdef PEGASUS_PLATFORM_OS400_ISERIES_IBM
207 #pragma convert(37)
|
208 h.sterling 1.63 const char* env = getenv("PEGASUS_MAX_BACKLOG_CONNECTION_QUEUE");
209 EtoA(env);
|
210 a.arora 1.51 #pragma convert(0)
211 #else
|
212 h.sterling 1.63 const char* env = getenv("PEGASUS_MAX_BACKLOG_CONNECTION_QUEUE");
|
213 a.arora 1.51 #endif
|
214 h.sterling 1.63 if(!env){
215 MAX_CONNECTION_QUEUE_LENGTH = 15;
|
216 david.dillard 1.64 }else{
|
217 h.sterling 1.63 char *end = NULL;
218 MAX_CONNECTION_QUEUE_LENGTH = strtol(env, &end, 10);
219 if(*end)
220 MAX_CONNECTION_QUEUE_LENGTH = 15;
221 cout << " MAX_CONNECTION_QUEUE_LENGTH = " << MAX_CONNECTION_QUEUE_LENGTH << endl;
222 }
|
223 a.arora 1.51 }
224 */
225 MAX_CONNECTION_QUEUE_LENGTH = 15;
|
226 david.dillard 1.64
|
227 mike 1.2 }
228
229 HTTPAcceptor::~HTTPAcceptor()
230 {
|
231 konrad.r 1.70 destroyConnections();
|
232 mday 1.7 unbind();
|
233 kumpf 1.25 // ATTN: Is this correct in a multi-HTTPAcceptor server?
|
234 mday 1.7 Socket::uninitializeInterface();
|
235 mike 1.2 }
236
|
237 mday 1.7 void HTTPAcceptor::handleEnqueue(Message *message)
|
238 mike 1.2 {
|
239 mday 1.7 if (! message)
240 return;
|
241 david.dillard 1.64
|
242 konrad.r 1.68 PEGASUS_ASSERT(_rep != 0);
|
243 mday 1.7 switch (message->getType())
244 {
245 case SOCKET_MESSAGE:
246 {
|
247 w.white 1.81.8.1 SocketMessage* socketMessage = (SocketMessage*)message;
|
248 david.dillard 1.64
|
249 w.white 1.81.8.1 // If this is a connection request:
|
250 h.sterling 1.63
|
251 w.white 1.81.8.1 if (socketMessage->socket == _rep->socket &&
252 socketMessage->events & SocketMessage::READ)
253 {
254 _acceptConnection();
255 }
256 else
257 {
258 // ATTN! this can't happen!
|
259 kumpf 1.44 Tracer::trace(TRC_DISCARDED_DATA, Tracer::LEVEL2,
260 "HTTPAcceptor::handleEnqueue: Invalid SOCKET_MESSAGE received.");
|
261 w.white 1.81.8.1 }
262
263 break;
264 }
|
265 j.alex 1.81.8.2 #ifdef PEGASUS_OS_TYPE_WINDOWS
|
266 w.white 1.81.8.1 case NAMEDPIPE_MESSAGE:
267 {
268 NamedPipeMessage* namedPipeMessage = (NamedPipeMessage*)message;
269
270 // If this is a connection request:
271
|
272 j.alex 1.81.8.3 if (((namedPipeMessage->namedPipe.getPipe()) == ( _rep->namedPipeServer->getPipe())) &&
273 (namedPipeMessage->events & NamedPipeMessage::READ))
|
274 w.white 1.81.8.1 {
|
275 j.alex 1.81.8.2 _acceptNamedPipeConnection();
|
276 w.white 1.81.8.1 }
|
277 j.alex 1.81.8.3 else
|
278 w.white 1.81.8.1 {
279 // ATTN! this can't happen!
280 Tracer::trace(TRC_DISCARDED_DATA, Tracer::LEVEL2,
|
281 j.alex 1.81.8.2 "HTTPAcceptor::handleEnqueue: Invalid NAMEDPIPE_MESSAGE received.");
282 }
|
283 j.alex 1.81.8.3
|
284 w.white 1.81.8.1 break;
|
285 mday 1.7
286 }
|
287 j.alex 1.81.8.2 #endif
288 // may Need to close connection for Named Pipe too.....??
289 case CLOSE_CONNECTION_MESSAGE:
|
290 mday 1.7 {
|
291 david.dillard 1.64 CloseConnectionMessage* closeConnectionMessage
|
292 h.sterling 1.63 = (CloseConnectionMessage*)message;
293
294 AutoMutex autoMut(_rep->_connection_mut);
|
295 david.dillard 1.64
|
296 h.sterling 1.63 for (Uint32 i = 0, n = _rep->connections.size(); i < n; i++)
297 {
|
298 david.dillard 1.64 HTTPConnection* connection = _rep->connections[i];
|
299 david.dillard 1.74 PEGASUS_SOCKET socket = connection->getSocket();
|
300 mday 1.7
|
301 h.sterling 1.63 if (socket == closeConnectionMessage->socket)
302 {
303 _monitor->unsolicitSocketMessages(socket);
304 _rep->connections.remove(i);
|
305 kumpf 1.17 delete connection;
|
306 h.sterling 1.63 break;
307 }
308 }
|
309 david.dillard 1.64
|
310 h.sterling 1.63 break;
|
311 mday 1.7 }
|
312 mike 1.2
|
313 kumpf 1.10 default:
314 // ATTN: need unexpected message error!
|
315 kumpf 1.44 Tracer::trace(TRC_DISCARDED_DATA, Tracer::LEVEL2,
316 "HTTPAcceptor::handleEnqueue: Invalid MESSAGE received.");
|
317 mday 1.7 break;
318 };
|
319 mike 1.2
|
320 mday 1.7 delete message;
321 }
|
322 mike 1.2
323
|
324 mday 1.7 void HTTPAcceptor::handleEnqueue()
325 {
326 Message* message = dequeue();
|
327 mike 1.2
|
328 mday 1.7 if (!message)
|
329 kumpf 1.44 {
330 Tracer::trace(TRC_DISCARDED_DATA, Tracer::LEVEL2,
331 "HTTPAcceptor::handleEnqueue(): No message on queue.");
|
332 mday 1.7 return;
|
333 kumpf 1.44 }
|
334 david.dillard 1.64
|
335 mday 1.7 handleEnqueue(message);
|
336 mike 1.2
337 }
338
|
339 kumpf 1.25 void HTTPAcceptor::bind()
|
340 mike 1.2 {
|
341 humberto 1.30 if (_rep){
|
342 h.sterling 1.63 //l10n
|
343 david.dillard 1.64 //throw BindFailedException("HTTPAcceptor already bound");
|
344 humberto 1.34
|
345 humberto 1.30 MessageLoaderParms parms("Common.HTTPAcceptor.ALREADY_BOUND",
|
346 h.sterling 1.63 "HTTPAcceptor already bound");
|
347 humberto 1.34
|
348 kumpf 1.44 Tracer::trace(TRC_DISCARDED_DATA, Tracer::LEVEL2,
349 "HTTPAcceptor::bind: HTTPAcceptor already bound.");
|
350 humberto 1.30 throw BindFailedException(parms);
351 }
|
352 mike 1.2
|
353 kumpf 1.25 _rep = new HTTPAcceptorRep(_localConnection);
|
354 mike 1.2
|
355 mday 1.7 // bind address
356 _bind();
|
357 mike 1.2
|
358 mday 1.7 return;
|
359 mike 1.2 }
360
361 /**
|
362 mday 1.7 _bind - creates a new server socket and bind socket to the port address.
|
363 h.sterling 1.63 If PEGASUS_DISABLE_LOCAL_DOMAIN_SOCKET is not defined, the port number is ignored and
|
364 kumpf 1.11 a domain socket is bound.
|
365 mike 1.2 */
366 void HTTPAcceptor::_bind()
367 {
|
368 w.white 1.81.8.1 PEGASUS_STD(cout) << "in HTTPAcceptor::_bind at the begining" << PEGASUS_STD(endl);
|
369 j.alex 1.81.8.2 PEGASUS_STD(cout) << "in HTTPAcceptor::_bind before ASSERT" << PEGASUS_STD(endl);
|
370 mike 1.2
|
371 konrad.r 1.68 PEGASUS_ASSERT(_rep != 0);
|
372 mday 1.7 // Create address:
|
373 mike 1.2
|
374 j.alex 1.81.8.2 PEGASUS_STD(cout) << "in HTTPAcceptor::_bind before memset" << PEGASUS_STD(endl);
375
376
377 #ifdef PEGASUS_OS_TYPE_WINDOWS
378 if (!_localConnection)
379 {
380 memset(_rep->address, 0, sizeof(*_rep->address));
381 }
382 #else
|
383 kumpf 1.25 memset(_rep->address, 0, sizeof(*_rep->address));
|
384 j.alex 1.81.8.2 #endif
385
386 PEGASUS_STD(cout) << "in HTTPAcceptor::_bind After memset" << PEGASUS_STD(endl);
387
388
389 if (_localConnection)
390 {
|
391 kumpf 1.6
|
392 j.alex 1.81.8.2 #ifdef PEGASUS_OS_TYPE_WINDOWS
393 PEGASUS_STD(cout) << "in HTTPAcceptor::_bind before calling _createNamedPipe() " << PEGASUS_STD(endl);
394 // _rep->createNamedPipe();
|
395 w.white 1.81.8.1 _createNamedPipe();
396 PEGASUS_STD(cout) << "in HTTPAcceptor::_bind after calling _createNamedPipe() " << PEGASUS_STD(endl);
|
397 j.alex 1.81.8.2 // Not sure if we need to continue to bind non local domain sockets in windows.....
|
398 w.white 1.81.8.1 return;
|
399 j.alex 1.81.8.2 // #else
400 #endif
|
401 w.white 1.81.8.1
|
402 j.alex 1.81.8.2 #ifndef PEGASUS_DISABLE_LOCAL_DOMAIN_SOCKET
403
|
404 w.white 1.81.8.1 reinterpret_cast<struct sockaddr_un*>(_rep->address)->sun_family =
|
405 kumpf 1.25 AF_UNIX;
406 strcpy(reinterpret_cast<struct sockaddr_un*>(_rep->address)->sun_path,
|
407 w.white 1.81.8.1 PEGASUS_LOCAL_DOMAIN_SOCKET_PATH);
|
408 chuck 1.38 #ifdef PEGASUS_PLATFORM_OS400_ISERIES_IBM
409 AtoE(reinterpret_cast<struct sockaddr_un*>(_rep->address)->sun_path);
410 #endif
|
411 kumpf 1.25 ::unlink(reinterpret_cast<struct sockaddr_un*>(_rep->address)->sun_path);
|
412 kumpf 1.6 #else
|
413 kumpf 1.25 PEGASUS_ASSERT(false);
|
414 kumpf 1.11 #endif
|
415 kumpf 1.25 }
416 else
417 {
418 reinterpret_cast<struct sockaddr_in*>(_rep->address)->sin_addr.s_addr =
419 INADDR_ANY;
420 reinterpret_cast<struct sockaddr_in*>(_rep->address)->sin_family =
421 AF_INET;
422 reinterpret_cast<struct sockaddr_in*>(_rep->address)->sin_port =
423 htons(_portNumber);
424 }
|
425 mike 1.2
|
426 mday 1.7 // Create socket:
|
427 david.dillard 1.64
|
428 kumpf 1.25 if (_localConnection)
429 {
430 _rep->socket = socket(AF_UNIX, SOCK_STREAM, 0);
431 }
432 else
433 {
434 _rep->socket = socket(PF_INET, SOCK_STREAM, IPPROTO_TCP);
|
435 mike 1.79
436 _setTCPNoDelay(_rep->socket);
|
437 kumpf 1.25 }
|
438 mike 1.2
|
439 mday 1.7 if (_rep->socket < 0)
440 {
441 delete _rep;
442 _rep = 0;
|
443 humberto 1.30 //l10n
444 //throw BindFailedException("Failed to create socket");
445 MessageLoaderParms parms("Common.HTTPAcceptor.FAILED_CREATE_SOCKET",
|
446 h.sterling 1.63 "Failed to create socket");
|
447 kumpf 1.44 Tracer::trace(TRC_DISCARDED_DATA, Tracer::LEVEL2,
448 "HTTPAcceptor::_bind _rep->socket < 0");
|
449 humberto 1.30 throw BindFailedException(parms);
|
450 mday 1.7 }
451
|
452 mday 1.28
453 // set the close-on-exec bit for this file handle.
|
454 david.dillard 1.64 // any unix that forks needs this bit set.
|
455 david.dillard 1.78 #if !defined PEGASUS_OS_TYPE_WINDOWS && !defined(PEGASUS_OS_VMS)
|
456 mday 1.28 int sock_flags;
457 if( (sock_flags = fcntl(_rep->socket, F_GETFD, 0)) < 0)
458 {
|
459 kumpf 1.44 PEG_TRACE_STRING(TRC_DISCARDED_DATA, Tracer::LEVEL2,
460 "HTTPAcceptor::_bind: fcntl(F_GETFD) failed");
|
461 mday 1.28 }
462 else
463 {
464 sock_flags |= FD_CLOEXEC;
465 if (fcntl(_rep->socket, F_SETFD, sock_flags) < 0)
466 {
|
467 kumpf 1.44 PEG_TRACE_STRING(TRC_DISCARDED_DATA, Tracer::LEVEL2,
468 "HTTPAcceptor::_bind: fcntl(F_SETFD) failed");
|
469 mday 1.28 }
470 }
|
471 david.dillard 1.64 #endif
|
472 mday 1.28
473
|
474 mday 1.7 //
475 // Set the socket option SO_REUSEADDR to reuse the socket address so
476 // that we can rebind to a new socket using the same address when we
477 // need to resume the cimom as a result of a timeout during a Shutdown
478 // operation.
479 //
480 int opt=1;
481 if (setsockopt(_rep->socket, SOL_SOCKET, SO_REUSEADDR,
|
482 h.sterling 1.63 (char *)&opt, sizeof(opt)) < 0)
|
483 mday 1.7 {
|
484 mday 1.28 Socket::close(_rep->socket);
|
485 mday 1.7 delete _rep;
486 _rep = 0;
|
487 humberto 1.30 //l10n
488 //throw BindFailedException("Failed to set socket option");
489 MessageLoaderParms parms("Common.HTTPAcceptor.FAILED_SET_SOCKET_OPTION",
|
490 h.sterling 1.63 "Failed to set socket option");
|
491 kumpf 1.44 PEG_TRACE_STRING(TRC_DISCARDED_DATA, Tracer::LEVEL2,
492 "HTTPAcceptor::_bind: Failed to set socket option.");
|
493 humberto 1.30 throw BindFailedException(parms);
|
494 mday 1.7 }
495
|
496 david.dillard 1.64
497 //
|
498 mday 1.7 // Bind socket to port:
|
499 david.dillard 1.64 //
|
500 kumpf 1.25 if (::bind(_rep->socket, _rep->address, _rep->address_size) < 0)
|
501 mday 1.7 {
502 Socket::close(_rep->socket);
503 delete _rep;
504 _rep = 0;
|
505 humberto 1.30 //l10n
506 //throw BindFailedException("Failed to bind socket");
507 MessageLoaderParms parms("Common.HTTPAcceptor.FAILED_BIND_SOCKET",
|
508 h.sterling 1.63 "Failed to bind socket");
|
509 kumpf 1.44 PEG_TRACE_STRING(TRC_DISCARDED_DATA, Tracer::LEVEL2,
510 "HTTPAcceptor::_bind: Failed to bind socket.");
|
511 humberto 1.30 throw BindFailedException(parms);
|
512 mday 1.7 }
513
|
514 david.dillard 1.64
515 //
516 // Get the actual port value used if the caller specified a port value of 0.
517 //
518 if ( _portNumber == 0 )
519 {
520 sockaddr_in buf;
|
521 david.dillard 1.65 PEGASUS_SOCKLEN_T bufSize = sizeof(buf);
|
522 david.dillard 1.64 if ( getsockname(_rep->socket, reinterpret_cast<sockaddr *>(&buf), &bufSize) == 0 )
523 {
524 _portNumber = ntohs(buf.sin_port);
525 }
526 }
527
528
|
529 w.otsuka 1.54 //
530 // Change permissions on Linux local domain socket to allow writes by others.
531 //
|
532 h.sterling 1.63 #if !defined(PEGASUS_DISABLE_LOCAL_DOMAIN_SOCKET) && defined(PEGASUS_PLATFORM_LINUX_GENERIC_GNU)
|
533 w.otsuka 1.54 if (_localConnection)
534 {
|
535 david.dillard 1.64 if (::chmod( PEGASUS_LOCAL_DOMAIN_SOCKET_PATH,
536 S_IRUSR | S_IWUSR | S_IXUSR |
|
537 w.otsuka 1.54 S_IRGRP | S_IWGRP | S_IXGRP |
538 S_IROTH | S_IWOTH | S_IXOTH ) < 0 )
539 {
540 Socket::close(_rep->socket);
541 delete _rep;
542 _rep = 0;
543 //l10n
544 //throw BindFailedException("Failed to bind socket");
545 MessageLoaderParms parms("Common.HTTPAcceptor.FAILED_BIND_SOCKET",
|
546 h.sterling 1.63 "Failed to bind socket");
|
547 w.otsuka 1.54 PEG_TRACE_STRING(TRC_DISCARDED_DATA, Tracer::LEVEL2,
548 "HTTPAcceptor::_bind: Failed to set domain socket permissions.");
549 throw BindFailedException(parms);
550 }
551 }
552 #endif
553
|
554 kumpf 1.11 // Set up listening on the given socket:
|
555 mday 1.7
|
556 a.arora 1.51 //int const MAX_CONNECTION_QUEUE_LENGTH = 15;
|
557 mday 1.7
558 if (listen(_rep->socket, MAX_CONNECTION_QUEUE_LENGTH) < 0)
559 {
560 Socket::close(_rep->socket);
561 delete _rep;
562 _rep = 0;
|
563 humberto 1.30 //l10n
564 //throw BindFailedException("Failed to bind socket");
565 MessageLoaderParms parms("Common.HTTPAcceptor.FAILED_BIND_SOCKET",
|
566 h.sterling 1.63 "Failed to bind socket");
|
567 kumpf 1.44 PEG_TRACE_STRING(TRC_DISCARDED_DATA, Tracer::LEVEL2,
568 "HTTPAcceptor::_bind: Failed to bind socket(1).");
|
569 humberto 1.30 throw BindFailedException(parms);
|
570 mday 1.7 }
571
572 // Register to receive SocketMessages on this socket:
573
|
574 mday 1.21 if ( -1 == ( _entry_index = _monitor->solicitSocketMessages(
|
575 h.sterling 1.63 _rep->socket,
576 SocketMessage::READ | SocketMessage::EXCEPTION,
|
577 david.dillard 1.64 getQueueId(),
|
578 h.sterling 1.63 Monitor::ACCEPTOR)))
|
579 mday 1.7 {
580 Socket::close(_rep->socket);
581 delete _rep;
582 _rep = 0;
|
583 humberto 1.30 //l10n
584 //throw BindFailedException("Failed to solicit socket messaeges");
585 MessageLoaderParms parms("Common.HTTPAcceptor.FAILED_SOLICIT_SOCKET_MESSAGES",
|
586 h.sterling 1.63 "Failed to solicit socket messaeges");
|
587 kumpf 1.44 PEG_TRACE_STRING(TRC_DISCARDED_DATA, Tracer::LEVEL2,
588 "HTTPAcceptor::_bind: Failed to solicit socket messages(2).");
|
589 humberto 1.30 throw BindFailedException(parms);
|
590 mday 1.7 }
|
591 j.alex 1.81.8.2 PEGASUS_STD(cout) << "in HTTPAcceptor::_bind at the End" << PEGASUS_STD(endl);
592
|
593 mike 1.2 }
594
595 /**
|
596 mday 1.7 closeConnectionSocket - close the server listening socket to disallow
597 new client connections.
|
598 mike 1.2 */
599 void HTTPAcceptor::closeConnectionSocket()
600 {
|
601 mday 1.7 if (_rep)
602 {
603 // unregister the socket
|
604 kumpf 1.35
605 // ATTN - comment out - see CIMServer::stopClientConnection()
606 //_monitor->unsolicitSocketMessages(_rep->socket);
|
607 mday 1.7
608 // close the socket
609 Socket::close(_rep->socket);
|
610 j.alex 1.67 // Unlink Local Domain Socket Bug# 3312
611 if (_localConnection)
612 {
613 #ifndef PEGASUS_DISABLE_LOCAL_DOMAIN_SOCKET
|
614 denise.eckstein 1.71 PEG_TRACE_STRING(TRC_HTTP, Tracer::LEVEL2,
|
615 j.alex 1.67 "HTTPAcceptor::closeConnectionSocket Unlinking local connection." );
616 ::unlink(
617 reinterpret_cast<struct sockaddr_un*>(_rep->address)->sun_path);
618 #else
619 PEGASUS_ASSERT(false);
620 #endif
621 }
622
|
623 mday 1.7 }
|
624 kumpf 1.44 else
625 {
626 PEG_TRACE_STRING(TRC_DISCARDED_DATA, Tracer::LEVEL2,
627 "HTTPAcceptor::closeConnectionSocket failure _rep is null." );
628 }
|
629 mike 1.2 }
630
631 /**
|
632 mday 1.7 reopenConnectionSocket - creates a new server socket.
|
633 mike 1.2 */
634 void HTTPAcceptor::reopenConnectionSocket()
635 {
|
636 mday 1.7 if (_rep)
637 {
638 _bind();
639 }
|
640 kumpf 1.44 else
641 {
642 PEG_TRACE_STRING(TRC_DISCARDED_DATA, Tracer::LEVEL2,
643 "HTTPAcceptor::reopenConnectionSocket failure _rep is null." );
644 }
|
645 mike 1.2 }
646
647 /**
|
648 mday 1.7 getOutstandingRequestCount - returns the number of outstanding requests.
|
649 mike 1.2 */
|
650 david.dillard 1.64 Uint32 HTTPAcceptor::getOutstandingRequestCount() const
|
651 mike 1.2 {
|
652 mday 1.28 Uint32 count = 0;
|
653 konrad.r 1.68 if (_rep)
|
654 mday 1.7 {
|
655 konrad.r 1.68 AutoMutex autoMut(_rep->_connection_mut);
656 if (_rep->connections.size() > 0)
657 {
658 HTTPConnection* connection = _rep->connections[0];
659 count = connection->getRequestCount();
660 }
|
661 mday 1.7 }
|
662 mday 1.28 return count;
|
663 mike 1.2 }
664
|
665 david.dillard 1.64
666 /**
667 getPortNumber - returns the port number used for the connection
668 */
669 Uint32 HTTPAcceptor::getPortNumber() const
670 {
671 return _portNumber;
672 }
673
|
674 mike 1.2 void HTTPAcceptor::unbind()
675 {
|
676 mday 1.7 if (_rep)
677 {
|
678 david.dillard 1.64 _portNumber = 0;
|
679 mday 1.7 Socket::close(_rep->socket);
|
680 kumpf 1.25
681 if (_localConnection)
682 {
|
683 h.sterling 1.63 #ifndef PEGASUS_DISABLE_LOCAL_DOMAIN_SOCKET
|
684 kumpf 1.25 ::unlink(
685 reinterpret_cast<struct sockaddr_un*>(_rep->address)->sun_path);
686 #else
687 PEGASUS_ASSERT(false);
688 #endif
689 }
690
|
691 mday 1.7 delete _rep;
692 _rep = 0;
693 }
|
694 kumpf 1.44 else
695 {
696 PEG_TRACE_STRING(TRC_DISCARDED_DATA, Tracer::LEVEL2,
697 "HTTPAcceptor::unbind failure _rep is null." );
698 }
|
699 mike 1.2 }
700
701 void HTTPAcceptor::destroyConnections()
702 {
|
703 konrad.r 1.68 if (_rep)
704 {
705 // For each connection created by this object:
|
706 mday 1.28
|
707 konrad.r 1.68 AutoMutex autoMut(_rep->_connection_mut);
708 for (Uint32 i = 0, n = _rep->connections.size(); i < n; i++)
709 {
710 HTTPConnection* connection = _rep->connections[i];
|
711 david.dillard 1.74 PEGASUS_SOCKET socket = connection->getSocket();
|
712 mike 1.2
|
713 konrad.r 1.68 // Unsolicit SocketMessages:
|
714 mike 1.2
|
715 konrad.r 1.68 _monitor->unsolicitSocketMessages(socket);
|
716 mike 1.2
|
717 konrad.r 1.68 // Destroy the connection (causing it to close):
|
718 mike 1.2
|
719 mike 1.75 while (connection->refcount.get()) { }
|
720 konrad.r 1.68 delete connection;
721 }
|
722 mike 1.2
|
723 konrad.r 1.68 _rep->connections.clear();
|
724 mday 1.7 }
|
725 mike 1.2 }
726
727 void HTTPAcceptor::_acceptConnection()
728 {
|
729 mday 1.7 // This function cannot be called on an invalid socket!
|
730 mike 1.2
|
731 mday 1.7 PEGASUS_ASSERT(_rep != 0);
|
732 mike 1.2
|
733 mday 1.7 if (!_rep)
734 return;
|
735 mike 1.2
|
736 mday 1.7 // Accept the connection (populate the address):
|
737 mike 1.2
|
738 kumpf 1.25 struct sockaddr* accept_address;
|
739 mike 1.77 PEGASUS_SOCKLEN_T address_size;
|
740 mike 1.2
|
741 kumpf 1.25 if (_localConnection)
742 {
|
743 h.sterling 1.63 #ifndef PEGASUS_DISABLE_LOCAL_DOMAIN_SOCKET
|
744 kumpf 1.25 accept_address = reinterpret_cast<struct sockaddr*>(new struct sockaddr_un);
745 address_size = sizeof(struct sockaddr_un);
|
746 mike 1.2 #else
|
747 kumpf 1.25 PEGASUS_ASSERT(false);
|
748 mike 1.2 #endif
|
749 kumpf 1.25 }
750 else
751 {
752 accept_address = reinterpret_cast<struct sockaddr*>(new struct sockaddr_in);
753 address_size = sizeof(struct sockaddr_in);
754 }
755
|
756 david.dillard 1.73 PEGASUS_SOCKET socket = accept(_rep->socket, accept_address, &address_size);
|
757 kumpf 1.25
758 delete accept_address;
|
759 mike 1.2
|
760 mday 1.7 if (socket < 0)
761 {
|
762 mday 1.36
|
763 david 1.27 Logger::put(Logger::STANDARD_LOG, System::CIMSERVER, Logger::TRACE,
|
764 h.sterling 1.63 "HTTPAcceptor - accept() failure. errno: $0"
765 ,errno);
|
766 david 1.27
|
767 kumpf 1.44 PEG_TRACE_STRING(TRC_DISCARDED_DATA, Tracer::LEVEL2,
|
768 kumpf 1.19 "HTTPAcceptor: accept() failed");
|
769 mday 1.7 return;
770 }
|
771 david 1.27
|
772 david.dillard 1.64 // set the close on exec flag
|
773 david.dillard 1.78 #if !defined(PEGASUS_OS_TYPE_WINDOWS) && !defined(PEGASUS_OS_VMS)
|
774 mday 1.28 int sock_flags;
775 if( (sock_flags = fcntl(socket, F_GETFD, 0)) < 0)
776 {
|
777 kumpf 1.44 PEG_TRACE_STRING(TRC_DISCARDED_DATA, Tracer::LEVEL2,
|
778 mday 1.28 "HTTPAcceptor: fcntl(F_GETFD) failed");
779 }
780 else
781 {
782 sock_flags |= FD_CLOEXEC;
783 if (fcntl(socket, F_SETFD, sock_flags) < 0)
784 {
|
785 kumpf 1.44 PEG_TRACE_STRING(TRC_DISCARDED_DATA, Tracer::LEVEL2,
|
786 mday 1.28 "HTTPAcceptor: fcntl(F_SETFD) failed");
787 }
788 }
|
789 david.dillard 1.64 #endif
|
790 mday 1.28
791
|
792 mike 1.76 PEG_LOGGER_TRACE((Logger::STANDARD_LOG, System::CIMSERVER, 0,
793 "HTTPAcceptor - accept() success. Socket: $1" ,socket));
|
794 mike 1.2
|
795 kumpf 1.72 AutoPtr<MP_Socket> mp_socket(new MP_Socket(
796 socket, _sslcontext, _sslContextObjectLock, _exportConnection));
|
797 mike 1.2
|
798 kumpf 1.72 // Perform the SSL handshake, if applicable. Make the socket non-blocking
799 // for this operation so we can send it back to the Monitor's select() loop
800 // if it takes a while.
801
802 mp_socket->disableBlocking();
803 Sint32 socketAcceptStatus = mp_socket->accept();
804 mp_socket->enableBlocking();
|
805 nag.boranna 1.59
|
806 kumpf 1.72 if (socketAcceptStatus < 0)
|
807 kumpf 1.19 {
|
808 nag.boranna 1.61 PEG_TRACE_STRING(TRC_DISCARDED_DATA, Tracer::LEVEL2,
|
809 kumpf 1.19 "HTTPAcceptor: SSL_accept() failed");
|
810 nag.boranna 1.61 mp_socket->close();
811 return;
|
812 mday 1.7 }
|
813 mike 1.2
|
814 kumpf 1.72 // Create a new connection and add it to the connection list:
815
|
816 david.dillard 1.64 HTTPConnection* connection = new HTTPConnection(_monitor, mp_socket,
|
817 kumpf 1.49 this, static_cast<MessageQueue *>(_outputMessageQueue), _exportConnection);
|
818 mike 1.2
|
819 kumpf 1.72 if (socketAcceptStatus == 0)
820 {
821 PEG_TRACE_STRING(TRC_HTTP, Tracer::LEVEL2,
822 "HTTPAcceptor: SSL_accept() pending");
823 connection->_acceptPending = true;
824 }
825
|
826 mday 1.7 // Solicit events on this new connection's socket:
|
827 mday 1.21 int index;
|
828 david.dillard 1.64
|
829 mday 1.22 if (-1 == (index = _monitor->solicitSocketMessages(
|
830 h.sterling 1.63 connection->getSocket(),
831 SocketMessage::READ | SocketMessage::EXCEPTION,
832 connection->getQueueId(), Monitor::CONNECTION)) )
|
833 mday 1.7 {
|
834 kumpf 1.37 // ATTN-DE-P2-2003100503::TODO::Need to enhance code to return
835 // an error message to Client application.
|
836 kumpf 1.44 Tracer::trace(TRC_DISCARDED_DATA, Tracer::LEVEL2,
837 "HTTPAcceptor::_acceptConnection: Attempt to allocate entry in _entries table failed.");
|
838 mday 1.7 delete connection;
839 Socket::close(socket);
|
840 kumpf 1.37 return;
|
841 mday 1.7 }
|
842 a.arora 1.48
|
843 mday 1.7 // Save the socket for cleanup later:
|
844 mday 1.21 connection->_entry_index = index;
|
845 a.arora 1.50 AutoMutex autoMut(_rep->_connection_mut);
|
846 mday 1.7 _rep->connections.append(connection);
|
847 mike 1.2 }
|
848 mday 1.32
|
849 j.alex 1.81.8.2 #ifdef PEGASUS_OS_TYPE_WINDOWS
|
850 w.white 1.81.8.1 void HTTPAcceptor::_createNamedPipe()
851 {
852 PEGASUS_STD(cout) << "in HTTPAcceptor::_createNamedPipe() at the begining" << PEGASUS_STD(endl);
853
|
854 j.alex 1.81.8.2 _rep->namedPipeServer = new NamedPipeServer("\\\\.\\pipe\\MyNamedPipe");
|
855 w.white 1.81.8.1 PEGASUS_STD(cout) << "in HTTPAcceptor::_createNamedPipe() after calling the pipe server constructor" << PEGASUS_STD(endl);
856
857
858
859 // Register to receive Messages on Connection pipe:
860
861 if ( -1 == ( _entry_index = _monitor->solicitPipeMessages(
|
862 j.alex 1.81.8.2 *_rep->namedPipeServer,
863 NamedPipeMessage::READ | NamedPipeMessage::EXCEPTION,
|
864 w.white 1.81.8.1 getQueueId(),
865 Monitor::ACCEPTOR)))
866 {
|
867 j.alex 1.81.8.2 ::CloseHandle(_rep->namedPipeServer->getPipe());
868 delete _rep;
869 _rep = 0;
870 //l10n
871 //throw BindFailedException("Failed to solicit socket messaeges");
872 MessageLoaderParms parms("Common.HTTPAcceptor.FAILED_SOLICIT_SOCKET_MESSAGES",
873 "Failed to solicit socket messaeges");
874 PEG_TRACE_STRING(TRC_DISCARDED_DATA, Tracer::LEVEL2,
875 "HTTPAcceptor::_bind: Failed to solicit socket messages(2).");
876 throw BindFailedException(parms);
877
|
878 w.white 1.81.8.1 PEGASUS_STD(cout) << "in HTTPAcceptor::_createNamedPipe() _monitor->solicitSocketMessages failed" << PEGASUS_STD(endl);
879
880 }
881
882 PEGASUS_STD(cout) << "in HTTPAcceptor::_createNamedPipe() at the end" << PEGASUS_STD(endl);
883 return;
884
885 }
|
886 j.alex 1.81.8.2 #endif
|
887 w.white 1.81.8.1
|
888 j.alex 1.81.8.2
889 #ifdef PEGASUS_OS_TYPE_WINDOWS
890 void HTTPAcceptor::_acceptNamedPipeConnection()
|
891 w.white 1.81.8.1 {
|
892 j.alex 1.81.8.2 PEGASUS_ASSERT(_rep != 0);
893
894 if (!_rep)
895 return;
896
|
897 w.white 1.81.8.1 cout <<"In HTTPAcceptor::_acceptNamedPipeConnection " << endl;
898
|
899 j.alex 1.81.8.2 // shouldnt we be using the private var....
900 // _namedPipeServer->accept()
901
902 NamedPipeServerEndPiont nPSEndPoint = _rep->namedPipeServer->accept();
903 // Registerpe to receive Messages on Connection pipe:
|
904 w.white 1.81.8.1
|
905 j.alex 1.81.8.2 cout << " In _acceptNamedPipeConnection -- after calling namedPipeServer->accept()" << endl;
906
907 HTTPConnection* connection = new HTTPConnection(_monitor, nPSEndPoint,
908 this, static_cast<MessageQueue *>(_outputMessageQueue), _exportConnection);
909
910 /* NOT SURE WHAT TO DO HERE ....
911 if (socketAcceptStatus == 0)
912 {
913 PEG_TRACE_STRING(TRC_HTTP, Tracer::LEVEL2,
914 "HTTPAcceptor: SSL_accept() pending");
915 connection->_acceptPending = true;
916 }
917
918 */
919
920 // Solicit events on this new connection's socket:
921 int index;
922
923 if (-1 == (index = _monitor->solicitPipeMessages(
924 connection->getNamedPipe(),
925 NamedPipeMessage::READ | NamedPipeMessage::EXCEPTION,
926 j.alex 1.81.8.2 connection->getQueueId(), Monitor::CONNECTION)) )
927 {
928 // ATTN-DE-P2-2003100503::TODO::Need to enhance code to return
929 // an error message to Client application.
930 Tracer::trace(TRC_DISCARDED_DATA, Tracer::LEVEL2,
931 "HTTPAcceptor::_acceptPipeConnection: Attempt to allocate entry in _entries table failed.");
932 delete connection;
933 // May have to close the PIPE here...
934 //Socket::close(socket);
935 return;
936 }
937
938 // Save the socket for cleanup later:
939 connection->_entry_index = index;
940 AutoMutex autoMut(_rep->_connection_mut);
941 _rep->connections.append(connection);
942
943 PEGASUS_STD(cout)
944 << "in HTTPAcceptor::_acceptNamedPipeConnection() at the end" << PEGASUS_STD(endl);
|
945 w.white 1.81.8.1
946
947 }
|
948 j.alex 1.81.8.2 #endif
|
949 w.white 1.81.8.1
|
950 mike 1.2 PEGASUS_NAMESPACE_END
|