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 thilo.boehm 1.74 PEG_METHOD_ENTER(TRC_HTTP, "HTTPConnector::~HTTPConnector()");
|
197 kumpf 1.72 delete _rep;
198 Socket::uninitializeInterface();
|
199 thilo.boehm 1.74 PEG_METHOD_EXIT();
|
200 mike 1.2 }
201
|
202 mday 1.4 void HTTPConnector::handleEnqueue(Message *message)
|
203 mike 1.2 {
|
204 kumpf 1.72 if (!message)
205 return;
|
206 mike 1.2
|
207 kumpf 1.72 switch (message->getType())
208 {
209 // It might be useful to catch socket messages later to implement
210 // asynchronous establishment of connections.
|
211 mike 1.2
|
212 kumpf 1.72 case SOCKET_MESSAGE:
213 break;
|
214 h.sterling 1.55
|
215 kumpf 1.72 case CLOSE_CONNECTION_MESSAGE:
|
216 h.sterling 1.55 {
|
217 kumpf 1.72 CloseConnectionMessage* closeConnectionMessage =
218 (CloseConnectionMessage*)message;
219
220 for (Uint32 i = 0, n = _rep->connections.size(); i < n; i++)
221 {
222 HTTPConnection* connection = _rep->connections[i];
223 SocketHandle socket = connection->getSocket();
224
225 if (socket == closeConnectionMessage->socket)
226 {
227 _monitor->unsolicitSocketMessages(socket);
228 _rep->connections.remove(i);
229 delete connection;
230 break;
231 }
232 }
|
233 h.sterling 1.55 }
|
234 mday 1.4
|
235 kumpf 1.72 default:
236 // ATTN: need unexpected message error!
237 break;
238 }
|
239 mday 1.4
|
240 kumpf 1.72 delete message;
|
241 mday 1.4 }
|
242 mike 1.2
243
|
244 mday 1.4 void HTTPConnector::handleEnqueue()
245 {
|
246 kumpf 1.72 Message* message = dequeue();
|
247 mday 1.4
|
248 kumpf 1.72 if (!message)
249 return;
|
250 mday 1.4
|
251 kumpf 1.72 handleEnqueue(message);
|
252 mike 1.2 }
253
254 HTTPConnection* HTTPConnector::connect(
|
255 kumpf 1.72 const String& host,
256 const Uint32 portNumber,
257 SSLContext * sslContext,
258 MessageQueue* outputMessageQueue)
|
259 mike 1.2 {
|
260 kumpf 1.75 PEG_METHOD_ENTER(TRC_HTTP, "HTTPConnector::connect()");
|
261 thilo.boehm 1.74
|
262 kumpf 1.72 SocketHandle socket;
|
263 kumpf 1.10
|
264 h.sterling 1.55 #ifndef PEGASUS_DISABLE_LOCAL_DOMAIN_SOCKET
|
265 kumpf 1.72 if (host == String::EMPTY)
266 {
267 // Set up the domain socket for a local connection
268
269 sockaddr_un address;
270 address.sun_family = AF_UNIX;
271 strcpy(address.sun_path, PEGASUS_LOCAL_DOMAIN_SOCKET_PATH);
|
272 chuck 1.41 #ifdef PEGASUS_PLATFORM_OS400_ISERIES_IBM
|
273 kumpf 1.72 AtoE(address.sun_path);
|
274 chuck 1.41 #endif
|
275 kumpf 1.10
|
276 kumpf 1.72 socket = Socket::createSocket(AF_UNIX, SOCK_STREAM, 0);
277 if (socket == PEGASUS_INVALID_SOCKET)
|
278 thilo.boehm 1.74 {
279 PEG_METHOD_EXIT();
|
280 kumpf 1.72 throw CannotCreateSocketException();
|
281 thilo.boehm 1.74 }
282
|
283 kumpf 1.72
284 // Connect the socket to the address:
285
286 if (::connect(socket,
287 reinterpret_cast<sockaddr*>(&address),
288 sizeof(address)) < 0)
289 {
290 MessageLoaderParms parms(
291 "Common.HTTPConnector.CONNECTION_FAILED_LOCAL_CIM_SERVER",
292 "Cannot connect to local CIM server. Connection failed.");
293 Socket::close(socket);
|
294 thilo.boehm 1.74 PEG_METHOD_EXIT();
|
295 kumpf 1.72 throw CannotConnectException(parms);
296 }
297 }
298 else
299 {
|
300 kumpf 1.10 #endif
301
|
302 kumpf 1.72 // Make the internet address:
303
304 sockaddr_in address;
305
306 if (!_MakeAddress((const char*)host.getCString(), portNumber, address))
307 {
308 char portStr [32];
309 sprintf (portStr, "%u", portNumber);
|
310 thilo.boehm 1.74 PEG_METHOD_EXIT();
|
311 kumpf 1.72 throw InvalidLocatorException(host + ":" + portStr);
312 }
|
313 mike 1.2
314
|
315 kumpf 1.72 // Create the socket:
316 socket = Socket::createSocket(PF_INET, SOCK_STREAM, IPPROTO_TCP);
317 if (socket == PEGASUS_INVALID_SOCKET)
|
318 thilo.boehm 1.74 {
319 PEG_METHOD_EXIT();
|
320 kumpf 1.72 throw CannotCreateSocketException();
|
321 thilo.boehm 1.74 }
322
|
323 kumpf 1.72
324 // Conect the socket to the address:
325 if (::connect(socket,
326 reinterpret_cast<sockaddr*>(&address),
327 sizeof(address)) < 0)
328 {
329 char portStr[32];
330 sprintf(portStr, "%u", portNumber);
331 MessageLoaderParms parms(
332 "Common.HTTPConnector.CONNECTION_FAILED_TO",
333 "Cannot connect to $0:$1. Connection failed.",
334 host,
335 portStr);
336 Socket::close(socket);
|
337 thilo.boehm 1.74 PEG_METHOD_EXIT();
|
338 kumpf 1.72 throw CannotConnectException(parms);
339 }
|
340 kumpf 1.10
|
341 h.sterling 1.55 #ifndef PEGASUS_DISABLE_LOCAL_DOMAIN_SOCKET
|
342 kumpf 1.72 }
|
343 kumpf 1.10 #endif
|
344 mike 1.2
|
345 kumpf 1.72 // Create HTTPConnection object:
346
|
347 kumpf 1.76 SharedPtr<MP_Socket> mp_socket(new MP_Socket(socket, sslContext, 0));
|
348 kumpf 1.72 if (mp_socket->connect() < 0)
349 {
350 char portStr[32];
351 sprintf(portStr, "%u", portNumber);
352 MessageLoaderParms parms(
353 "Common.HTTPConnector.CONNECTION_FAILED_TO",
354 "Cannot connect to $0:$1. Connection failed.",
355 host,
356 portStr);
357 mp_socket->close();
|
358 thilo.boehm 1.74 PEG_METHOD_EXIT();
|
359 kumpf 1.72 throw CannotConnectException(parms);
360 }
|
361 mike 1.2
|
362 kumpf 1.72 HTTPConnection* connection = new HTTPConnection(
|
363 kumpf 1.70 _monitor, mp_socket, String::EMPTY, this,
364 static_cast<MessageQueueService *>(outputMessageQueue));
|
365 mike 1.2
|
366 kumpf 1.72 // Solicit events on this new connection's socket:
|
367 mike 1.2
|
368 kumpf 1.72 if (-1 == (_entry_index = _monitor->solicitSocketMessages(
369 connection->getSocket(),
370 SocketMessage::READ | SocketMessage::EXCEPTION,
371 connection->getQueueId(), Monitor::CONNECTOR)))
372 {
373 (connection->getMPSocket()).close();
374 }
|
375 mike 1.2
|
376 kumpf 1.72 // Save the socket for cleanup later:
|
377 a.arora 1.47
|
378 kumpf 1.72 _rep->connections.append(connection);
|
379 thilo.boehm 1.74 PEG_METHOD_EXIT();
|
380 kumpf 1.72 return connection;
|
381 mike 1.2 }
382
383 void HTTPConnector::destroyConnections()
384 {
|
385 kumpf 1.72 // For each connection created by this object:
|
386 mike 1.2
|
387 kumpf 1.72 for (Uint32 i = 0, n = _rep->connections.size(); i < n; i++)
388 {
389 _deleteConnection(_rep->connections[i]);
390 }
|
391 mike 1.2
|
392 kumpf 1.72 _rep->connections.clear();
|
393 mike 1.2 }
394
|
395 mday 1.32
|
396 kumpf 1.7 void HTTPConnector::disconnect(HTTPConnection* currentConnection)
397 {
398 //
399 // find and delete the specified connection
400 //
|
401 denise.eckstein 1.56
402 Uint32 index = PEG_NOT_FOUND;
|
403 kumpf 1.7 for (Uint32 i = 0, n = _rep->connections.size(); i < n; i++)
404 {
405 if (currentConnection == _rep->connections[i])
406 {
|
407 denise.eckstein 1.56 index = i;
408 break;
409 }
410 }
411
412 PEGASUS_ASSERT(index != PEG_NOT_FOUND);
|
413 tony 1.34
|
414 mike 1.66 SocketHandle socket = currentConnection->getSocket();
|
415 denise.eckstein 1.56 _monitor->unsolicitSocketMessages(socket);
416 _rep->connections.remove(index);
417 delete currentConnection;
|
418 kumpf 1.7 }
|
419 kumpf 1.9
420 void HTTPConnector::_deleteConnection(HTTPConnection* httpConnection)
|
421 dj.gorey 1.45 {
|
422 mike 1.66 SocketHandle socket = httpConnection->getSocket();
|
423 dj.gorey 1.45
424 // Unsolicit SocketMessages:
425
426 _monitor->unsolicitSocketMessages(socket);
427
428 // Destroy the connection (causing it to close):
429
430 delete httpConnection;
431 }
432
|
433 mike 1.2 PEGASUS_NAMESPACE_END
|