(file) Return to HTTPConnector.cpp CVS log (file) (dir) Up to [Pegasus] / pegasus / src / Pegasus / Common

  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

No CVS admin address has been configured
Powered by
ViewCVS 0.9.2