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