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

  1 karl  1.22 //%2006////////////////////////////////////////////////////////////////////////
  2 mike  1.2  //
  3 karl  1.17 // 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.14 // IBM Corp.; EMC Corporation, The Open Group.
  7 karl  1.17 // 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.18 // Copyright (c) 2005 Hewlett-Packard Development Company, L.P.; IBM Corp.;
 10            // EMC Corporation; VERITAS Software Corporation; The Open Group.
 11 karl  1.22 // 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.4  // 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 karl  1.22 // 
 21 kumpf 1.4  // 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.4  // 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            #include "Socket.h"
 35 mike  1.23 #include "Network.h"
 36            #include <cctype>
 37            #include <cstring>
 38            #include <Pegasus/Common/Sharable.h>
 39 thilo.boehm 1.25 #include <Pegasus/Common/Logger.h>
 40                  #include <Pegasus/Common/System.h>
 41 kumpf       1.28 #include <Pegasus/Common/Tracer.h>
 42 kumpf       1.32.4.2 #include <Pegasus/Common/Threads.h>
 43 mike        1.23     
 44 kumpf       1.28     PEGASUS_NAMESPACE_BEGIN
 45                      
 46                      static Uint32 _socketInterfaceRefCount = 0;
 47                      
 48                      Boolean Socket::timedConnect(
 49                          SocketHandle socket,
 50                          sockaddr* address,
 51                          int addressLength,
 52                          Uint32 timeoutMilliseconds)
 53                      {
 54                          int connectResult;
 55 kumpf       1.32.4.2 #ifdef PEGASUS_OS_TYPE_WINDOWS
 56                          connectResult = ::connect(socket, address, addressLength);
 57                      #else
 58                          Boolean connectionAlreadyRefused = false;
 59                          Uint32 maxConnectAttempts = 100;
 60                          // Retry the connect() until it succeeds or it fails with an error other
 61                          // than EINTR, EAGAIN (for Linux), or the first ECONNREFUSED (for HP-UX).
 62                          while (((connectResult = ::connect(socket, address, addressLength)) == -1)
 63                                 && (maxConnectAttempts-- > 0)
 64                                 && ((errno == EINTR) || (errno == EAGAIN) ||
 65                                     ((errno == ECONNREFUSED) && !connectionAlreadyRefused)))
 66                          {
 67                              if (errno == ECONNREFUSED)
 68                              {
 69                                  connectionAlreadyRefused = true;
 70                              }
 71                              Threads::sleep(1);
 72                          }
 73                      #endif
 74 kumpf       1.28     
 75                          if (connectResult == 0)
 76                          {
 77                              return true;
 78                          }
 79 mike        1.2      
 80 kumpf       1.28         if (getSocketError() == PEGASUS_NETWORK_EINPROGRESS)
 81                          {
 82                              PEG_TRACE((TRC_HTTP, Tracer::LEVEL4,
 83                                  "Connection to server in progress.  Waiting up to %u milliseconds "
 84                                      "for the socket to become connected.",
 85                                  timeoutMilliseconds));
 86                      
 87                              fd_set fdwrite;
 88                              FD_ZERO(&fdwrite);
 89                              FD_SET(socket, &fdwrite);
 90                              struct timeval timeoutValue =
 91                                  { timeoutMilliseconds/1000, timeoutMilliseconds%1000*1000 };
 92                              int selectResult = -1;
 93 mike        1.2      
 94 venkat.puvvada 1.32.4.1 #ifdef PEGASUS_OS_TYPE_WINDOWS
 95                                 PEGASUS_RETRY_SYSTEM_CALL(
 96                                     select(FD_SETSIZE, NULL, &fdwrite, &fdwrite, &timeoutValue),
 97                                     selectResult);
 98                         #else
 99 kumpf          1.28             PEGASUS_RETRY_SYSTEM_CALL(
100                                     select(FD_SETSIZE, NULL, &fdwrite, NULL, &timeoutValue),
101                                     selectResult);
102 venkat.puvvada 1.32.4.1 #endif
103 kumpf          1.28             if (selectResult == 0)
104                                 {
105 marek          1.32                 PEG_TRACE_CSTRING(TRC_HTTP, Tracer::LEVEL1,
106 kumpf          1.28                     "select() timed out waiting for the socket connection to be "
107                                             "established.");
108                                     return false;
109                                 }
110                                 else if (selectResult > 0)
111                                 {
112                                     int optval;
113                                     SocketLength optlen = sizeof(int);
114                                     getsockopt(socket, SOL_SOCKET, SO_ERROR, (char*)&optval, &optlen);
115                                     if (optval == 0)
116                                     {
117                                         PEG_TRACE_CSTRING(TRC_HTTP, Tracer::LEVEL4,
118                                             "Connection with server established.");
119                                         return true;
120                                     }
121                                     else
122                                     {
123 marek          1.32                     PEG_TRACE((TRC_HTTP, Tracer::LEVEL1,
124 kumpf          1.28                         "Did not connect, getsockopt() returned optval = %d",
125                                             optval));
126                                         return false;
127                                     }
128                                 }
129                                 else
130                                 {
131 marek          1.32                 PEG_TRACE((TRC_HTTP, Tracer::LEVEL1,
132 kumpf          1.28                     "select() returned error code %d",
133                                         getSocketError()));
134                                     return false;
135                                 }
136                             }
137 mike           1.2      
138 marek          1.32         PEG_TRACE((TRC_HTTP, Tracer::LEVEL1,
139 kumpf          1.28             "connect() returned error code %d",
140                                 getSocketError()));
141                             return false;
142                         }
143 mike           1.2      
144 mike           1.23     Sint32 Socket::read(SocketHandle socket, void* ptr, Uint32 size)
145 mike           1.2      {
146                         #ifdef PEGASUS_OS_TYPE_WINDOWS
147                             return ::recv(socket, (char*)ptr, size, 0);
148                         #else
149 mike           1.23         int status;
150                             PEGASUS_RETRY_SYSTEM_CALL(::read(socket, (char*)ptr, size), status);
151                             return status;
152 mday           1.11     #endif
153 mike           1.2      }
154                         
155 mike           1.23     Sint32 Socket::write(SocketHandle socket, const void* ptr, Uint32 size)
156 mike           1.2      {
157                         #ifdef PEGASUS_OS_TYPE_WINDOWS
158                             return ::send(socket, (const char*)ptr, size, 0);
159                         #else
160 mike           1.23         int status;
161                             PEGASUS_RETRY_SYSTEM_CALL(::write(socket, (char*)ptr, size), status);
162                             return status;
163 mday           1.11     #endif
164 mike           1.2      }
165                         
166 kumpf          1.26     Sint32 Socket::timedWrite(
167                             SocketHandle socket,
168                             const void* ptr,
169                             Uint32 size,
170                             Uint32 socketWriteTimeout)
171 marek          1.24     {
172                             Sint32 bytesWritten = 0;
173                             Sint32 totalBytesWritten = 0;
174                             Boolean socketTimedOut = false;
175                             int selreturn = 0;
176                             while (1)
177                             {
178                         #ifdef PEGASUS_OS_TYPE_WINDOWS
179                                 PEGASUS_RETRY_SYSTEM_CALL(
180                                     ::send(socket, (const char*)ptr, size, 0), bytesWritten);
181                         #else
182                                 PEGASUS_RETRY_SYSTEM_CALL(
183                                     ::write(socket, (char*)ptr, size), bytesWritten);
184                         #endif
185 kumpf          1.26             // Some data written this cycle ?
186 marek          1.24             // Add it to the total amount of written data.
187                                 if (bytesWritten > 0)
188                                 {
189                                     totalBytesWritten += bytesWritten;
190                                     socketTimedOut = false;
191                                 }
192                         
193                                 // All data written ? return amount of data written
194                                 if ((Uint32)bytesWritten == size)
195                                 {
196                                     return totalBytesWritten;
197                                 }
198                                 // If data has been written partially, we resume writing data
199                                 // this also accounts for the case of a signal interrupt
200                                 // (i.e. errno = EINTR)
201                                 if (bytesWritten > 0)
202                                 {
203                                     size -= bytesWritten;
204                                     ptr = (void *)((char *)ptr + bytesWritten);
205                                     continue;
206                                 }
207 marek          1.24             // Something went wrong
208                                 if (bytesWritten == PEGASUS_SOCKET_ERROR)
209                                 {
210                                     // if we already waited for the socket to get ready, bail out
211 kumpf          1.26                 if (socketTimedOut) return bytesWritten;
212 marek          1.24     #ifdef PEGASUS_OS_TYPE_WINDOWS
213                                     if (WSAGetLastError() == WSAEWOULDBLOCK)
214                         #else
215                                     if (errno == EAGAIN || errno == EWOULDBLOCK)
216                         #endif
217                                     {
218                                         fd_set fdwrite;
219                                          // max. timeout seconds waiting for the socket to get ready
220                                         struct timeval tv = { socketWriteTimeout, 0 };
221                                         FD_ZERO(&fdwrite);
222                                         FD_SET(socket, &fdwrite);
223                                         selreturn = select(FD_SETSIZE, NULL, &fdwrite, NULL, &tv);
224                                         if (selreturn == 0) socketTimedOut = true; // ran out of time
225 kumpf          1.26                     continue;
226 marek          1.24                 }
227                                     return bytesWritten;
228                                 }
229                             }
230                         }
231                         
232 kumpf          1.29     void Socket::close(SocketHandle& socket)
233 mike           1.2      {
234 kumpf          1.29         if (socket != PEGASUS_INVALID_SOCKET)
235 mike           1.23         {
236                         #ifdef PEGASUS_OS_TYPE_WINDOWS
237 kumpf          1.26             if (!closesocket(socket))
238 kumpf          1.29             {
239                                     socket = PEGASUS_INVALID_SOCKET;
240                                 }
241 mike           1.23     #else
242 kumpf          1.26             int status;
243                                 PEGASUS_RETRY_SYSTEM_CALL(::close(socket), status);
244 mike           1.23     
245 kumpf          1.26             if (status == 0)
246 kumpf          1.29             {
247                                     socket = PEGASUS_INVALID_SOCKET;
248                                 }
249 mike           1.23     #endif
250                             }
251 mike           1.2      }
252                         
253 mike           1.23     void Socket::disableBlocking(SocketHandle socket)
254 mike           1.2      {
255                         #ifdef PEGASUS_OS_TYPE_WINDOWS
256 kumpf          1.28         unsigned long flag = 1;    // Use "flag = 0" to enable blocking
257 mike           1.2          ioctlsocket(socket, FIONBIO, &flag);
258 carson.hovey   1.31     #elif PEGASUS_OS_VMS
259                             int flag=1;                // Use "flag = 0" to enable blocking
260                             ioctl(socket, FIONBIO, &flag);
261 mike           1.2      #else
262                             int flags = fcntl(socket, F_GETFL, 0);
263 kumpf          1.28         flags |= O_NONBLOCK;    // Use "flags &= ~O_NONBLOCK" to enable blocking
264 mike           1.2          fcntl(socket, F_SETFL, flags);
265                         #endif
266                         }
267                         
268                         void Socket::initializeInterface()
269                         {
270                         #ifdef PEGASUS_OS_TYPE_WINDOWS
271                             if (_socketInterfaceRefCount == 0)
272                             {
273 david.dillard  1.20             WSADATA tmp;
274 mike           1.2      
275 kumpf          1.30             int err = WSAStartup(0x202, &tmp);
276                                 if (err != 0)
277                                 {
278                                     throw Exception(MessageLoaderParms(
279                                         "Common.Socket.WSASTARTUP_FAILED.WINDOWS",
280                                         "WSAStartup failed with error $0.",
281                                         err));
282                                 }
283 mike           1.2          }
284                         
285                             _socketInterfaceRefCount++;
286                         #endif
287                         }
288                         
289                         void Socket::uninitializeInterface()
290                         {
291                         #ifdef PEGASUS_OS_TYPE_WINDOWS
292                             _socketInterfaceRefCount--;
293                         
294                             if (_socketInterfaceRefCount == 0)
295 david.dillard  1.20             WSACleanup();
296 mike           1.2      #endif
297                         }
298                         
299 thilo.boehm    1.25     //------------------------------------------------------------------------------
300                         //
301                         // _setTCPNoDelay()
302                         //
303                         //------------------------------------------------------------------------------
304                         
305                         inline void _setTCPNoDelay(SocketHandle socket)
306                         {
307                             // This function disables "Nagle's Algorithm" also known as "the TCP delay
308                             // algorithm", which causes read operations to obtain whatever data is
309 kumpf          1.26         // already in the input queue and then wait a little longer to see if
310                             // more data arrives. This algorithm optimizes the case in which data is
311                             // sent in only one direction but severely impairs performance of round
312                             // trip servers. Disabling TCP delay is a standard technique for round
313 thilo.boehm    1.25         // trip servers.
314                         
315                            int opt = 1;
316                            setsockopt(socket, IPPROTO_TCP, TCP_NODELAY, (char*)&opt, sizeof(opt));
317                         }
318                         //------------------------------------------------------------------------------
319                         //
320                         // _setInformIfNewTCPIP()
321                         //
322                         //------------------------------------------------------------------------------
323                         inline void _setInformIfNewTCPIP(SocketHandle socket)
324                         {
325                         #ifdef PEGASUS_OS_ZOS
326                            // This function enables the notification of the CIM Server that a new
327 kumpf          1.26        // TCPIP transport layer is active. This is needed to be aware of a
328 thilo.boehm    1.25        // restart of the transport layer. When this option is in effect,
329                            // the accetp(), select(), and read() request will receive an errno=EIO.
330                            // Once this happens, the socket should be closed and create a new.
331 kumpf          1.26     
332 thilo.boehm    1.25        int NewTcpipOn = 1;
333 kumpf          1.26        setibmsockopt(
334                                socket,
335                                SOL_SOCKET,
336                                SO_EioIfNewTP,
337                                (char*)&NewTcpipOn,
338                                sizeof(NewTcpipOn));
339 thilo.boehm    1.25     #endif
340                         }
341                         
342                         
343                         SocketHandle Socket::createSocket(int domain, int type, int protocol)
344                         {
345                             SocketHandle newSocket;
346                         
347 kumpf          1.26         if (domain == AF_UNIX)
348 thilo.boehm    1.25         {
349 kumpf          1.26             return socket(domain,type,protocol);
350 thilo.boehm    1.25         }
351                         
352                             bool sendTcpipMsg = true;
353                         
354 kumpf          1.26         while (1)
355 thilo.boehm    1.25         {
356                                 newSocket = socket(domain,type,protocol);
357                         
358 kumpf          1.27             if ((newSocket != PEGASUS_INVALID_SOCKET) ||
359                                     (getSocketError() != PEGASUS_NETWORK_TRYAGAIN))
360                                 {
361                                     break;
362                                 }
363                         
364                         #ifdef PEGASUS_OS_ZOS
365 thilo.boehm    1.25             // The program should wait for transport layer to become ready.
366                         
367 kumpf          1.27             if (sendTcpipMsg)
368 thilo.boehm    1.25             {
369 kumpf          1.27                 Logger::put_l(
370                                         Logger::STANDARD_LOG, System::CIMSERVER, Logger::INFORMATION,
371                                         "Common.Socket.WAIT_FOR_TCPIP",
372                                         "TCP/IP temporary unavailable.");
373                                     sendTcpipMsg = false;
374                                 }
375 thilo.boehm    1.25     
376 kumpf          1.27             System::sleep(30);
377                         #endif
378 thilo.boehm    1.25         } // wait for the transport layer become ready.
379                         
380                             // Is the socket in an unrecoverable error ?
381                             if (newSocket == PEGASUS_INVALID_SOCKET)
382                             {
383                                 // return immediate
384 kumpf          1.26             return PEGASUS_INVALID_SOCKET;
385                             }
386                             else
387                             {
388 thilo.boehm    1.25             // set aditional socket options
389                                 _setTCPNoDelay(newSocket);
390                                 _setInformIfNewTCPIP(newSocket);
391                         
392 kumpf          1.26             return newSocket;
393 thilo.boehm    1.25         }
394                         }
395                         
396 mike           1.2      PEGASUS_NAMESPACE_END

No CVS admin address has been configured
Powered by
ViewCVS 0.9.2