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