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

No CVS admin address has been configured
Powered by
ViewCVS 0.9.2