1 karl 1.63 //%2006////////////////////////////////////////////////////////////////////////
|
2 mike 1.2 //
|
3 karl 1.50 // 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.50 // 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.53 // Copyright (c) 2005 Hewlett-Packard Development Company, L.P.; IBM Corp.;
10 // EMC Corporation; VERITAS Software Corporation; The Open Group.
|
11 karl 1.63 // 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.16 // 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 //
|
21 kumpf 1.16 // 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.16 // 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 mike 1.67 #include "Network.h"
|
35 mike 1.2 #include "Config.h"
36 #include <iostream>
|
37 kumpf 1.12 #include "Constants.h"
|
38 mike 1.2 #include "Socket.h"
|
39 kumpf 1.73 #include <Pegasus/Common/MessageLoader.h>
|
40 kumpf 1.85 #include <Pegasus/Common/Network.h>
|
41 mike 1.2 #include "Socket.h"
42 #include "TLS.h"
43 #include "HTTPConnector.h"
44 #include "HTTPConnection.h"
|
45 dave.sudlik 1.78 #include "HostAddress.h"
|
46 mike 1.2
|
47 marek 1.44 #ifdef PEGASUS_OS_ZOS
|
48 kumpf 1.72 # include <resolv.h> // MAXHOSTNAMELEN
|
49 marek 1.44 #endif
50
|
51 mike 1.2 PEGASUS_USING_STD;
52
53 PEGASUS_NAMESPACE_BEGIN
54
|
55 a.arora 1.46 class bsd_socket_rep;
56
|
57 mike 1.2 ////////////////////////////////////////////////////////////////////////////////
58 //
59 // Local routines:
60 //
61 ////////////////////////////////////////////////////////////////////////////////
62
63 static Boolean _MakeAddress(
|
64 kumpf 1.72 const char* hostname,
65 int port,
|
66 dave.sudlik 1.78 sockaddr_in& address,
|
67 dave.sudlik 1.79 void **addrInfoRoot)
|
68 mike 1.2 {
|
69 kumpf 1.72 if (!hostname)
70 return false;
|
71 david 1.38
|
72 dave.sudlik 1.78 #ifdef PEGASUS_ENABLE_IPV6
73 struct sockaddr_in6 serveraddr;
74 struct addrinfo hints;
75 struct addrinfo *result;
76
77 memset(&hints, 0x00, sizeof(hints));
78 hints.ai_family = AF_UNSPEC ;
79 hints.ai_socktype = SOCK_STREAM;
80
81 // Giving hint as AI_NUMERICHOST to the getaddrinfo function avoids
82 // name resolution done by getaddrinfo at DNS. This will improve
83 // performance.
84
85 // Check for valid IPv4 address.
86 if (1 == HostAddress::convertTextToBinary(AF_INET, hostname, &serveraddr))
87 {
88 hints.ai_family = AF_INET;
89 hints.ai_flags |= AI_NUMERICHOST;
90 } // check for valid IPv6 address
91 else if (1 == HostAddress::convertTextToBinary(AF_INET6, hostname,
92 &serveraddr))
93 dave.sudlik 1.78 {
94 hints.ai_family = AF_INET6;
95 hints.ai_flags |= AI_NUMERICHOST;
96 }
97
98 char portStr[20];
99 sprintf(portStr,"%d",port);
|
100 dmitry.mikulin 1.83 if (System::getAddrInfo(hostname, portStr, &hints, &result))
|
101 dave.sudlik 1.78 {
102 return false;
103 }
|
104 dave.sudlik 1.79 *addrInfoRoot = result;
|
105 dave.sudlik 1.78 #else
106
|
107 dave.sudlik 1.49 ////////////////////////////////////////////////////////////////////////////////
108 // This code used to check if the first character of "hostname" was alphabetic
|
109 kumpf 1.72 // to indicate hostname instead of IP address. But RFC 1123, section 2.1,
110 // relaxed this requirement to alphabetic character *or* digit. So bug 1462
111 // changed the flow here to call inet_addr first to check for a valid IP
112 // address in dotted decimal notation. If it's not a valid IP address, then
113 // try to validate it as a hostname.
114 // RFC 1123 states: The host SHOULD check the string syntactically for a
115 // dotted-decimal number before looking it up in the Domain Name System.
|
116 dave.sudlik 1.49 // Hence the call to inet_addr() first.
117 ////////////////////////////////////////////////////////////////////////////////
118
|
119 kumpf 1.72 unsigned long tmp_addr = inet_addr((char *)hostname);
120 struct hostent* hostEntry;
|
121 dave.sudlik 1.49
122 // Note: 0xFFFFFFFF is actually a valid IP address (255.255.255.255).
123 // A better solution would be to use inet_aton() or equivalent, as
124 // inet_addr() is now considered "obsolete".
125
|
126 kumpf 1.72 if (tmp_addr == 0xFFFFFFFF) // if hostname is not an IP address
127 {
128 char hostEntryBuffer[8192];
129 struct hostent hostEntryStruct;
|
130 dmitry.mikulin 1.83 hostEntry = System::getHostByName(hostname,
131 &hostEntryStruct,
132 (char*) &hostEntryBuffer,
133 sizeof (hostEntryBuffer));
|
134 kumpf 1.72
135 if (!hostEntry)
136 {
137 return false;
138 }
|
139 mike 1.2
|
140 kumpf 1.72 memset(&address, 0, sizeof(address));
141 memcpy(&address.sin_addr, hostEntry->h_addr, hostEntry->h_length);
142 address.sin_family = hostEntry->h_addrtype;
143 address.sin_port = htons(port);
144 }
145 else // else hostname *is* a dotted-decimal IP address
146 {
147 memset(&address, 0, sizeof(address));
148 address.sin_family = AF_INET;
149 address.sin_addr.s_addr = tmp_addr;
150 address.sin_port = htons(port);
151 }
|
152 dave.sudlik 1.78 #endif // PEGASUS_ENABLE_IPV6
|
153 kumpf 1.72
154 return true;
|
155 mike 1.2 }
156
157 ////////////////////////////////////////////////////////////////////////////////
158 //
159 // HTTPConnectorRep
160 //
161 ////////////////////////////////////////////////////////////////////////////////
162
163 struct HTTPConnectorRep
164 {
|
165 kumpf 1.72 Array<HTTPConnection*> connections;
|
166 mike 1.2 };
167
168 ////////////////////////////////////////////////////////////////////////////////
169 //
170 // HTTPConnector
171 //
172 ////////////////////////////////////////////////////////////////////////////////
173
174 HTTPConnector::HTTPConnector(Monitor* monitor)
|
175 kumpf 1.72 : Base(PEGASUS_QUEUENAME_HTTPCONNECTOR),
176 _monitor(monitor), _entry_index(-1)
|
177 mike 1.2 {
|
178 kumpf 1.72 _rep = new HTTPConnectorRep;
179 Socket::initializeInterface();
|
180 mike 1.2 }
181
182 HTTPConnector::~HTTPConnector()
183 {
|
184 thilo.boehm 1.74 PEG_METHOD_ENTER(TRC_HTTP, "HTTPConnector::~HTTPConnector()");
|
185 kumpf 1.72 delete _rep;
186 Socket::uninitializeInterface();
|
187 thilo.boehm 1.74 PEG_METHOD_EXIT();
|
188 mike 1.2 }
189
|
190 mday 1.4 void HTTPConnector::handleEnqueue(Message *message)
|
191 mike 1.2 {
|
192 kumpf 1.72 if (!message)
193 return;
|
194 mike 1.2
|
195 kumpf 1.72 switch (message->getType())
196 {
197 // It might be useful to catch socket messages later to implement
198 // asynchronous establishment of connections.
|
199 mike 1.2
|
200 kumpf 1.72 case SOCKET_MESSAGE:
201 break;
|
202 h.sterling 1.55
|
203 kumpf 1.72 case CLOSE_CONNECTION_MESSAGE:
|
204 h.sterling 1.55 {
|
205 kumpf 1.72 CloseConnectionMessage* closeConnectionMessage =
206 (CloseConnectionMessage*)message;
207
208 for (Uint32 i = 0, n = _rep->connections.size(); i < n; i++)
209 {
210 HTTPConnection* connection = _rep->connections[i];
211 SocketHandle socket = connection->getSocket();
212
213 if (socket == closeConnectionMessage->socket)
214 {
215 _monitor->unsolicitSocketMessages(socket);
216 _rep->connections.remove(i);
217 delete connection;
218 break;
219 }
220 }
|
221 h.sterling 1.55 }
|
222 mday 1.4
|
223 kumpf 1.72 default:
224 // ATTN: need unexpected message error!
225 break;
226 }
|
227 mday 1.4
|
228 kumpf 1.72 delete message;
|
229 mday 1.4 }
|
230 mike 1.2
231
|
232 mday 1.4 void HTTPConnector::handleEnqueue()
233 {
|
234 kumpf 1.72 Message* message = dequeue();
|
235 mday 1.4
|
236 kumpf 1.72 if (!message)
237 return;
|
238 mday 1.4
|
239 kumpf 1.72 handleEnqueue(message);
|
240 mike 1.2 }
241
242 HTTPConnection* HTTPConnector::connect(
|
243 kumpf 1.72 const String& host,
244 const Uint32 portNumber,
245 SSLContext * sslContext,
|
246 kumpf 1.85 Uint32 timeoutMilliseconds,
|
247 kumpf 1.72 MessageQueue* outputMessageQueue)
|
248 mike 1.2 {
|
249 kumpf 1.75 PEG_METHOD_ENTER(TRC_HTTP, "HTTPConnector::connect()");
|
250 thilo.boehm 1.74
|
251 mike 1.80 SocketHandle socket = -1;
|
252 kumpf 1.10
|
253 h.sterling 1.55 #ifndef PEGASUS_DISABLE_LOCAL_DOMAIN_SOCKET
|
254 kumpf 1.72 if (host == String::EMPTY)
255 {
256 // Set up the domain socket for a local connection
257
258 sockaddr_un address;
259 address.sun_family = AF_UNIX;
260 strcpy(address.sun_path, PEGASUS_LOCAL_DOMAIN_SOCKET_PATH);
|
261 kumpf 1.10
|
262 kumpf 1.72 socket = Socket::createSocket(AF_UNIX, SOCK_STREAM, 0);
263 if (socket == PEGASUS_INVALID_SOCKET)
|
264 thilo.boehm 1.74 {
265 PEG_METHOD_EXIT();
|
266 kumpf 1.72 throw CannotCreateSocketException();
|
267 thilo.boehm 1.74 }
268
|
269 kumpf 1.85 Socket::disableBlocking(socket);
|
270 kumpf 1.72
271 // Connect the socket to the address:
272
|
273 kumpf 1.85 if (!Socket::timedConnect(
274 socket,
|
275 kumpf 1.72 reinterpret_cast<sockaddr*>(&address),
|
276 kumpf 1.85 sizeof(address),
277 timeoutMilliseconds))
|
278 kumpf 1.72 {
279 MessageLoaderParms parms(
280 "Common.HTTPConnector.CONNECTION_FAILED_LOCAL_CIM_SERVER",
281 "Cannot connect to local CIM server. Connection failed.");
282 Socket::close(socket);
|
283 thilo.boehm 1.74 PEG_METHOD_EXIT();
|
284 kumpf 1.72 throw CannotConnectException(parms);
285 }
286 }
287 else
|
288 kumpf 1.85 #endif
|
289 kumpf 1.72 {
|
290 kumpf 1.85 // Set up the IP socket connection
|
291 kumpf 1.10
|
292 kumpf 1.72 // Make the internet address:
|
293 dave.sudlik 1.78 #ifdef PEGASUS_ENABLE_IPV6
|
294 dave.sudlik 1.79 struct addrinfo *addrInfo, *addrInfoRoot;
|
295 dave.sudlik 1.78 #endif
|
296 kumpf 1.72 sockaddr_in address;
|
297 dave.sudlik 1.78 if (!_MakeAddress((const char*)host.getCString(), portNumber, address,
298 #ifdef PEGASUS_ENABLE_IPV6
|
299 mike 1.80 (void**)(void*)&addrInfoRoot
|
300 dave.sudlik 1.78 #else
301 0
302 #endif
303 ))
|
304 kumpf 1.72 {
305 char portStr [32];
306 sprintf (portStr, "%u", portNumber);
|
307 thilo.boehm 1.74 PEG_METHOD_EXIT();
|
308 kumpf 1.72 throw InvalidLocatorException(host + ":" + portStr);
309 }
|
310 mike 1.2
|
311 dave.sudlik 1.78 #ifdef PEGASUS_ENABLE_IPV6
|
312 dave.sudlik 1.79 addrInfo = addrInfoRoot;
313 while (addrInfo)
|
314 dave.sudlik 1.78 {
315 // Create the socket:
|
316 dave.sudlik 1.79 socket = Socket::createSocket(addrInfo->ai_family,
317 addrInfo->ai_socktype, addrInfo->ai_protocol);
|
318 dave.sudlik 1.78 #else
319 socket = Socket::createSocket(PF_INET, SOCK_STREAM, IPPROTO_TCP);
320 #endif
321 if (socket == PEGASUS_INVALID_SOCKET)
322 {
|
323 dave.sudlik 1.79 #ifdef PEGASUS_ENABLE_IPV6
324 freeaddrinfo(addrInfoRoot);
325 #endif
|
326 dave.sudlik 1.78 PEG_METHOD_EXIT();
327 throw CannotCreateSocketException();
328 }
|
329 kumpf 1.72
|
330 kumpf 1.85 Socket::disableBlocking(socket);
331
332 // Connect the socket to the address:
333 if (!Socket::timedConnect(
334 socket,
|
335 dave.sudlik 1.78 #ifdef PEGASUS_ENABLE_IPV6
|
336 kumpf 1.85 reinterpret_cast<sockaddr*>(addrInfo->ai_addr),
337 addrInfo->ai_addrlen,
|
338 dave.sudlik 1.78 #else
|
339 kumpf 1.85 reinterpret_cast<sockaddr*>(&address),
340 sizeof(address),
|
341 dave.sudlik 1.78 #endif
|
342 kumpf 1.85 timeoutMilliseconds))
|
343 dave.sudlik 1.78 {
344 #ifdef PEGASUS_ENABLE_IPV6
|
345 dave.sudlik 1.79 addrInfo = addrInfo->ai_next;
346 if (addrInfo)
|
347 dave.sudlik 1.78 {
348 Socket::close(socket);
349 continue;
350 }
351 #endif
|
352 kumpf 1.85 char portStr[32];
353 sprintf(portStr, "%u", portNumber);
354 MessageLoaderParms parms(
355 "Common.HTTPConnector.CONNECTION_FAILED_TO",
356 "Cannot connect to $0:$1. Connection failed.",
357 host,
358 portStr);
359 Socket::close(socket);
|
360 dave.sudlik 1.79 #ifdef PEGASUS_ENABLE_IPV6
|
361 kumpf 1.85 freeaddrinfo(addrInfoRoot);
|
362 dave.sudlik 1.79 #endif
|
363 kumpf 1.85 PEG_METHOD_EXIT();
364 throw CannotConnectException(parms);
365 }
|
366 dave.sudlik 1.78 #ifdef PEGASUS_ENABLE_IPV6
367 break;
368 }
|
369 dave.sudlik 1.79 freeaddrinfo(addrInfoRoot);
|
370 dave.sudlik 1.78 #endif
|
371 kumpf 1.72 }
|
372 mike 1.2
|
373 kumpf 1.72 // Create HTTPConnection object:
374
|
375 kumpf 1.76 SharedPtr<MP_Socket> mp_socket(new MP_Socket(socket, sslContext, 0));
|
376 kumpf 1.85
377 if (mp_socket->connect(timeoutMilliseconds) < 0)
|
378 kumpf 1.72 {
379 char portStr[32];
380 sprintf(portStr, "%u", portNumber);
381 MessageLoaderParms parms(
382 "Common.HTTPConnector.CONNECTION_FAILED_TO",
383 "Cannot connect to $0:$1. Connection failed.",
384 host,
385 portStr);
386 mp_socket->close();
|
387 thilo.boehm 1.74 PEG_METHOD_EXIT();
|
388 kumpf 1.72 throw CannotConnectException(parms);
389 }
|
390 mike 1.2
|
391 kumpf 1.72 HTTPConnection* connection = new HTTPConnection(
|
392 kumpf 1.70 _monitor, mp_socket, String::EMPTY, this,
393 static_cast<MessageQueueService *>(outputMessageQueue));
|
394 mike 1.2
|
395 kumpf 1.72 // Solicit events on this new connection's socket:
|
396 mike 1.2
|
397 kumpf 1.72 if (-1 == (_entry_index = _monitor->solicitSocketMessages(
398 connection->getSocket(),
399 SocketMessage::READ | SocketMessage::EXCEPTION,
|
400 kumpf 1.84 connection->getQueueId(), MonitorEntry::TYPE_CONNECTOR)))
|
401 kumpf 1.72 {
402 (connection->getMPSocket()).close();
403 }
|
404 mike 1.2
|
405 kumpf 1.72 // Save the socket for cleanup later:
|
406 a.arora 1.47
|
407 kumpf 1.72 _rep->connections.append(connection);
|
408 thilo.boehm 1.74 PEG_METHOD_EXIT();
|
409 kumpf 1.72 return connection;
|
410 mike 1.2 }
411
412 void HTTPConnector::destroyConnections()
413 {
|
414 kumpf 1.72 // For each connection created by this object:
|
415 mike 1.2
|
416 kumpf 1.72 for (Uint32 i = 0, n = _rep->connections.size(); i < n; i++)
417 {
418 _deleteConnection(_rep->connections[i]);
419 }
|
420 mike 1.2
|
421 kumpf 1.72 _rep->connections.clear();
|
422 mike 1.2 }
423
|
424 mday 1.32
|
425 kumpf 1.7 void HTTPConnector::disconnect(HTTPConnection* currentConnection)
426 {
427 //
428 // find and delete the specified connection
429 //
|
430 denise.eckstein 1.56
431 Uint32 index = PEG_NOT_FOUND;
|
432 kumpf 1.7 for (Uint32 i = 0, n = _rep->connections.size(); i < n; i++)
433 {
434 if (currentConnection == _rep->connections[i])
435 {
|
436 denise.eckstein 1.56 index = i;
437 break;
438 }
439 }
440
441 PEGASUS_ASSERT(index != PEG_NOT_FOUND);
|
442 tony 1.34
|
443 mike 1.66 SocketHandle socket = currentConnection->getSocket();
|
444 denise.eckstein 1.56 _monitor->unsolicitSocketMessages(socket);
445 _rep->connections.remove(index);
446 delete currentConnection;
|
447 kumpf 1.7 }
|
448 kumpf 1.9
449 void HTTPConnector::_deleteConnection(HTTPConnection* httpConnection)
|
450 dj.gorey 1.45 {
|
451 mike 1.66 SocketHandle socket = httpConnection->getSocket();
|
452 dj.gorey 1.45
453 // Unsolicit SocketMessages:
454
455 _monitor->unsolicitSocketMessages(socket);
456
457 // Destroy the connection (causing it to close):
458
459 delete httpConnection;
460 }
461
|
462 mike 1.2 PEGASUS_NAMESPACE_END
|