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 mike 1.2 #include "Socket.h"
41 #include "TLS.h"
42 #include "HTTPConnector.h"
43 #include "HTTPConnection.h"
44
|
45 david 1.38 #ifdef PEGASUS_OS_OS400
|
46 kumpf 1.72 # include "EBCDIC_OS400.h"
|
47 david 1.38 #endif
48
|
49 marek 1.44 #ifdef PEGASUS_OS_ZOS
|
50 kumpf 1.72 # include <resolv.h> // MAXHOSTNAMELEN
|
51 marek 1.44 #endif
52
|
53 mike 1.2 PEGASUS_USING_STD;
54
55 PEGASUS_NAMESPACE_BEGIN
56
|
57 a.arora 1.46 class bsd_socket_rep;
58
|
59 mike 1.2 ////////////////////////////////////////////////////////////////////////////////
60 //
61 // Local routines:
62 //
63 ////////////////////////////////////////////////////////////////////////////////
64
65 static Boolean _MakeAddress(
|
66 kumpf 1.72 const char* hostname,
67 int port,
68 sockaddr_in& address)
|
69 mike 1.2 {
|
70 kumpf 1.72 if (!hostname)
71 return false;
|
72 david 1.38
73 #ifdef PEGASUS_OS_OS400
74 char ebcdicHost[256];
75 if (strlen(hostname) < 256)
|
76 h.sterling 1.55 strcpy(ebcdicHost, hostname);
|
77 david 1.38 else
|
78 h.sterling 1.55 return false;
|
79 david 1.38 AtoE(ebcdicHost);
80 #endif
|
81 kumpf 1.72
|
82 dave.sudlik 1.49 ////////////////////////////////////////////////////////////////////////////////
83 // This code used to check if the first character of "hostname" was alphabetic
|
84 kumpf 1.72 // to indicate hostname instead of IP address. But RFC 1123, section 2.1,
85 // relaxed this requirement to alphabetic character *or* digit. So bug 1462
86 // changed the flow here to call inet_addr first to check for a valid IP
87 // address in dotted decimal notation. If it's not a valid IP address, then
88 // try to validate it as a hostname.
89 // RFC 1123 states: The host SHOULD check the string syntactically for a
90 // dotted-decimal number before looking it up in the Domain Name System.
|
91 dave.sudlik 1.49 // Hence the call to inet_addr() first.
92 ////////////////////////////////////////////////////////////////////////////////
93
94 #ifdef PEGASUS_OS_OS400
|
95 kumpf 1.72 unsigned long tmp_addr = inet_addr(ebcdicHost);
|
96 dave.sudlik 1.49 #else
|
97 kumpf 1.72 unsigned long tmp_addr = inet_addr((char *)hostname);
|
98 kumpf 1.62 #endif
|
99 dave.sudlik 1.49
|
100 kumpf 1.72 struct hostent* hostEntry;
|
101 dave.sudlik 1.49
102 // Note: 0xFFFFFFFF is actually a valid IP address (255.255.255.255).
103 // A better solution would be to use inet_aton() or equivalent, as
104 // inet_addr() is now considered "obsolete".
105
|
106 kumpf 1.72 if (tmp_addr == 0xFFFFFFFF) // if hostname is not an IP address
107 {
|
108 kumpf 1.62 #if defined(PEGASUS_OS_LINUX)
|
109 kumpf 1.72 char hostEntryBuffer[8192];
110 struct hostent hostEntryStruct;
111 int hostEntryErrno;
112
113 gethostbyname_r(
114 hostname,
115 &hostEntryStruct,
116 hostEntryBuffer,
117 sizeof(hostEntryBuffer),
118 &hostEntry,
119 &hostEntryErrno);
|
120 kumpf 1.62 #elif defined(PEGASUS_OS_SOLARIS)
|
121 kumpf 1.72 char hostEntryBuffer[8192];
122 struct hostent hostEntryStruct;
123 int hostEntryErrno;
124
125 hostEntry = gethostbyname_r(
126 (char *)hostname,
127 &hostEntryStruct,
128 hostEntryBuffer,
129 sizeof(hostEntryBuffer),
130 &hostEntryErrno);
|
131 david 1.38 #elif defined(PEGASUS_OS_OS400)
|
132 kumpf 1.72 hostEntry = gethostbyname(ebcdicHost);
|
133 marek 1.44 #elif defined(PEGASUS_OS_ZOS)
|
134 kumpf 1.72 if (String::equalNoCase("localhost",String(hostname)))
135 {
136 char hostName[PEGASUS_MAXHOSTNAMELEN + 1];
137 gethostname( hostName, sizeof( hostName ) );
138 hostName[sizeof(hostName)-1] = 0;
139 hostEntry = gethostbyname(hostName);
140 }
141 else
142 {
143 hostEntry = gethostbyname((char *)hostname);
144 }
|
145 keith.petley 1.36 #else
|
146 kumpf 1.72 hostEntry = gethostbyname((char *)hostname);
|
147 keith.petley 1.36 #endif
|
148 kumpf 1.72 if (!hostEntry)
149 {
150 return false;
151 }
|
152 mike 1.2
|
153 kumpf 1.72 memset(&address, 0, sizeof(address));
154 memcpy(&address.sin_addr, hostEntry->h_addr, hostEntry->h_length);
155 address.sin_family = hostEntry->h_addrtype;
156 address.sin_port = htons(port);
157 }
158 else // else hostname *is* a dotted-decimal IP address
159 {
160 memset(&address, 0, sizeof(address));
161 address.sin_family = AF_INET;
162 address.sin_addr.s_addr = tmp_addr;
163 address.sin_port = htons(port);
164 }
165
166 return true;
|
167 mike 1.2 }
168
169 ////////////////////////////////////////////////////////////////////////////////
170 //
171 // HTTPConnectorRep
172 //
173 ////////////////////////////////////////////////////////////////////////////////
174
175 struct HTTPConnectorRep
176 {
|
177 kumpf 1.72 Array<HTTPConnection*> connections;
|
178 mike 1.2 };
179
180 ////////////////////////////////////////////////////////////////////////////////
181 //
182 // HTTPConnector
183 //
184 ////////////////////////////////////////////////////////////////////////////////
185
186 HTTPConnector::HTTPConnector(Monitor* monitor)
|
187 kumpf 1.72 : Base(PEGASUS_QUEUENAME_HTTPCONNECTOR),
188 _monitor(monitor), _entry_index(-1)
|
189 mike 1.2 {
|
190 kumpf 1.72 _rep = new HTTPConnectorRep;
191 Socket::initializeInterface();
|
192 mike 1.2 }
193
194 HTTPConnector::~HTTPConnector()
195 {
|
196 kumpf 1.72 delete _rep;
197 Socket::uninitializeInterface();
|
198 mike 1.2 }
199
|
200 mday 1.4 void HTTPConnector::handleEnqueue(Message *message)
|
201 mike 1.2 {
|
202 kumpf 1.72 if (!message)
203 return;
|
204 mike 1.2
|
205 kumpf 1.72 switch (message->getType())
206 {
207 // It might be useful to catch socket messages later to implement
208 // asynchronous establishment of connections.
|
209 mike 1.2
|
210 kumpf 1.72 case SOCKET_MESSAGE:
211 break;
|
212 h.sterling 1.55
|
213 kumpf 1.72 case CLOSE_CONNECTION_MESSAGE:
|
214 h.sterling 1.55 {
|
215 kumpf 1.72 CloseConnectionMessage* closeConnectionMessage =
216 (CloseConnectionMessage*)message;
217
218 for (Uint32 i = 0, n = _rep->connections.size(); i < n; i++)
219 {
220 HTTPConnection* connection = _rep->connections[i];
221 SocketHandle socket = connection->getSocket();
222
223 if (socket == closeConnectionMessage->socket)
224 {
225 _monitor->unsolicitSocketMessages(socket);
226 _rep->connections.remove(i);
227 delete connection;
228 break;
229 }
230 }
|
231 h.sterling 1.55 }
|
232 mday 1.4
|
233 kumpf 1.72 default:
234 // ATTN: need unexpected message error!
235 break;
236 }
|
237 mday 1.4
|
238 kumpf 1.72 delete message;
|
239 mday 1.4 }
|
240 mike 1.2
241
|
242 mday 1.4 void HTTPConnector::handleEnqueue()
243 {
|
244 kumpf 1.72 Message* message = dequeue();
|
245 mday 1.4
|
246 kumpf 1.72 if (!message)
247 return;
|
248 mday 1.4
|
249 kumpf 1.72 handleEnqueue(message);
|
250 mike 1.2 }
251
252 HTTPConnection* HTTPConnector::connect(
|
253 kumpf 1.72 const String& host,
254 const Uint32 portNumber,
255 SSLContext * sslContext,
256 MessageQueue* outputMessageQueue)
|
257 mike 1.2 {
|
258 kumpf 1.72 SocketHandle socket;
|
259 kumpf 1.10
|
260 h.sterling 1.55 #ifndef PEGASUS_DISABLE_LOCAL_DOMAIN_SOCKET
|
261 kumpf 1.72 if (host == String::EMPTY)
262 {
263 // Set up the domain socket for a local connection
264
265 sockaddr_un address;
266 address.sun_family = AF_UNIX;
267 strcpy(address.sun_path, PEGASUS_LOCAL_DOMAIN_SOCKET_PATH);
|
268 chuck 1.41 #ifdef PEGASUS_PLATFORM_OS400_ISERIES_IBM
|
269 kumpf 1.72 AtoE(address.sun_path);
|
270 chuck 1.41 #endif
|
271 kumpf 1.10
|
272 kumpf 1.72 socket = Socket::createSocket(AF_UNIX, SOCK_STREAM, 0);
273 if (socket == PEGASUS_INVALID_SOCKET)
274 throw CannotCreateSocketException();
275
276 // Connect the socket to the address:
277
278 if (::connect(socket,
279 reinterpret_cast<sockaddr*>(&address),
280 sizeof(address)) < 0)
281 {
282 MessageLoaderParms parms(
283 "Common.HTTPConnector.CONNECTION_FAILED_LOCAL_CIM_SERVER",
284 "Cannot connect to local CIM server. Connection failed.");
285 Socket::close(socket);
286 throw CannotConnectException(parms);
287 }
288 }
289 else
290 {
|
291 kumpf 1.10 #endif
292
|
293 kumpf 1.72 // Make the internet address:
294
295 sockaddr_in address;
296
297 if (!_MakeAddress((const char*)host.getCString(), portNumber, address))
298 {
299 char portStr [32];
300 sprintf (portStr, "%u", portNumber);
301 throw InvalidLocatorException(host + ":" + portStr);
302 }
|
303 mike 1.2
304
|
305 kumpf 1.72 // Create the socket:
306 socket = Socket::createSocket(PF_INET, SOCK_STREAM, IPPROTO_TCP);
307 if (socket == PEGASUS_INVALID_SOCKET)
308 throw CannotCreateSocketException();
309
310 // Conect the socket to the address:
311 if (::connect(socket,
312 reinterpret_cast<sockaddr*>(&address),
313 sizeof(address)) < 0)
314 {
315 char portStr[32];
316 sprintf(portStr, "%u", portNumber);
317 MessageLoaderParms parms(
318 "Common.HTTPConnector.CONNECTION_FAILED_TO",
319 "Cannot connect to $0:$1. Connection failed.",
320 host,
321 portStr);
322 Socket::close(socket);
323 throw CannotConnectException(parms);
324 }
|
325 kumpf 1.10
|
326 h.sterling 1.55 #ifndef PEGASUS_DISABLE_LOCAL_DOMAIN_SOCKET
|
327 kumpf 1.72 }
|
328 kumpf 1.10 #endif
|
329 mike 1.2
|
330 kumpf 1.72 // Create HTTPConnection object:
331
332 AutoPtr<MP_Socket> mp_socket(new MP_Socket(socket, sslContext, 0));
333 if (mp_socket->connect() < 0)
334 {
335 char portStr[32];
336 sprintf(portStr, "%u", portNumber);
337 MessageLoaderParms parms(
338 "Common.HTTPConnector.CONNECTION_FAILED_TO",
339 "Cannot connect to $0:$1. Connection failed.",
340 host,
341 portStr);
342 mp_socket->close();
343 throw CannotConnectException(parms);
344 }
|
345 mike 1.2
|
346 kumpf 1.72 HTTPConnection* connection = new HTTPConnection(
|
347 kumpf 1.70 _monitor, mp_socket, String::EMPTY, this,
348 static_cast<MessageQueueService *>(outputMessageQueue));
|
349 mike 1.2
|
350 kumpf 1.72 // Solicit events on this new connection's socket:
|
351 mike 1.2
|
352 kumpf 1.72 if (-1 == (_entry_index = _monitor->solicitSocketMessages(
353 connection->getSocket(),
354 SocketMessage::READ | SocketMessage::EXCEPTION,
355 connection->getQueueId(), Monitor::CONNECTOR)))
356 {
357 (connection->getMPSocket()).close();
358 }
|
359 mike 1.2
|
360 kumpf 1.72 // Save the socket for cleanup later:
|
361 a.arora 1.47
|
362 kumpf 1.72 _rep->connections.append(connection);
|
363 mike 1.2
|
364 kumpf 1.72 return connection;
|
365 mike 1.2 }
366
367 void HTTPConnector::destroyConnections()
368 {
|
369 kumpf 1.72 // For each connection created by this object:
|
370 mike 1.2
|
371 kumpf 1.72 for (Uint32 i = 0, n = _rep->connections.size(); i < n; i++)
372 {
373 _deleteConnection(_rep->connections[i]);
374 }
|
375 mike 1.2
|
376 kumpf 1.72 _rep->connections.clear();
|
377 mike 1.2 }
378
|
379 mday 1.32
|
380 kumpf 1.7 void HTTPConnector::disconnect(HTTPConnection* currentConnection)
381 {
382 //
383 // find and delete the specified connection
384 //
|
385 denise.eckstein 1.56
386 Uint32 index = PEG_NOT_FOUND;
|
387 kumpf 1.7 for (Uint32 i = 0, n = _rep->connections.size(); i < n; i++)
388 {
389 if (currentConnection == _rep->connections[i])
390 {
|
391 denise.eckstein 1.56 index = i;
392 break;
393 }
394 }
395
396 PEGASUS_ASSERT(index != PEG_NOT_FOUND);
|
397 tony 1.34
|
398 mike 1.66 SocketHandle socket = currentConnection->getSocket();
|
399 denise.eckstein 1.56 _monitor->unsolicitSocketMessages(socket);
400 _rep->connections.remove(index);
401 delete currentConnection;
|
402 kumpf 1.7 }
|
403 kumpf 1.9
404 void HTTPConnector::_deleteConnection(HTTPConnection* httpConnection)
|
405 dj.gorey 1.45 {
|
406 mike 1.66 SocketHandle socket = httpConnection->getSocket();
|
407 dj.gorey 1.45
408 // Unsolicit SocketMessages:
409
410 _monitor->unsolicitSocketMessages(socket);
411
412 // Destroy the connection (causing it to close):
413
414 delete httpConnection;
415 }
416
|
417 mike 1.2 PEGASUS_NAMESPACE_END
|