(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.27.4.1 #include <Pegasus/Common/Tracer.h>
 42 mike        1.2      
 43                      PEGASUS_NAMESPACE_BEGIN
 44                      
 45                      static Uint32 _socketInterfaceRefCount = 0;
 46                      
 47 kumpf       1.27.4.1 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                      
 62                          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 kumpf       1.27.4.1 
 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                      
 76                              PEGASUS_RETRY_SYSTEM_CALL(
 77                                  select(FD_SETSIZE, NULL, &fdwrite, NULL, &timeoutValue),
 78                                  selectResult);
 79                              if (selectResult == 0)
 80                              {
 81                                  PEG_TRACE_CSTRING(TRC_HTTP, Tracer::LEVEL2,
 82                                      "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 kumpf       1.27.4.1             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                                      PEG_TRACE((TRC_HTTP, Tracer::LEVEL2,
100                                          "Did not connect, getsockopt() returned optval = %d",
101                                          optval));
102                                      return false;
103                                  }
104                              }
105                              else
106                              {
107                                  PEG_TRACE((TRC_HTTP, Tracer::LEVEL2,
108                                      "select() returned error code %d",
109                                      getSocketError()));
110 kumpf       1.27.4.1             return false;
111                              }
112                          }
113                      
114                          PEG_TRACE((TRC_HTTP, Tracer::LEVEL2,
115                              "connect() returned error code %d",
116                              getSocketError()));
117                          return false;
118                      }
119                      
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 mike        1.23     void Socket::close(SocketHandle socket)
209 mike        1.2      {
210 mike        1.23         if (socket != -1)
211                          {
212                      #ifdef PEGASUS_OS_TYPE_WINDOWS
213 kumpf       1.26             if (!closesocket(socket))
214                                  socket = -1;
215 mike        1.23     #else
216 kumpf       1.26             int status;
217                              PEGASUS_RETRY_SYSTEM_CALL(::close(socket), status);
218 mike        1.23     
219 kumpf       1.26             if (status == 0)
220                                  socket = -1;
221 mike        1.23     #endif
222                          }
223 mike        1.2      }
224                      
225 mike        1.23     void Socket::disableBlocking(SocketHandle socket)
226 mike        1.2      {
227                      #ifdef PEGASUS_OS_TYPE_WINDOWS
228 kumpf       1.27.4.1     unsigned long flag = 1;    // Use "flag = 0" to enable blocking
229 mike        1.2          ioctlsocket(socket, FIONBIO, &flag);
230                      #else
231                          int flags = fcntl(socket, F_GETFL, 0);
232 kumpf       1.27.4.1     flags |= O_NONBLOCK;    // Use "flags &= ~O_NONBLOCK" to enable blocking
233 mike        1.2          fcntl(socket, F_SETFL, flags);
234                      #endif
235                      }
236                      
237                      void Socket::initializeInterface()
238                      {
239                      #ifdef PEGASUS_OS_TYPE_WINDOWS
240                          if (_socketInterfaceRefCount == 0)
241                          {
242 david.dillard 1.20             WSADATA tmp;
243 mike          1.2      
244 kumpf         1.26             if (WSAStartup(0x202, &tmp) == SOCKET_ERROR)
245                                    WSACleanup();
246 mike          1.2          }
247                        
248                            _socketInterfaceRefCount++;
249                        #endif
250                        }
251                        
252                        void Socket::uninitializeInterface()
253                        {
254                        #ifdef PEGASUS_OS_TYPE_WINDOWS
255                            _socketInterfaceRefCount--;
256                        
257                            if (_socketInterfaceRefCount == 0)
258 david.dillard 1.20             WSACleanup();
259 mike          1.2      #endif
260                        }
261                        
262 thilo.boehm   1.25     //------------------------------------------------------------------------------
263                        //
264                        // _setTCPNoDelay()
265                        //
266                        //------------------------------------------------------------------------------
267                        
268                        inline void _setTCPNoDelay(SocketHandle socket)
269                        {
270                            // This function disables "Nagle's Algorithm" also known as "the TCP delay
271                            // algorithm", which causes read operations to obtain whatever data is
272 kumpf         1.26         // already in the input queue and then wait a little longer to see if
273                            // more data arrives. This algorithm optimizes the case in which data is
274                            // sent in only one direction but severely impairs performance of round
275                            // trip servers. Disabling TCP delay is a standard technique for round
276 thilo.boehm   1.25         // trip servers.
277                        
278                           int opt = 1;
279                           setsockopt(socket, IPPROTO_TCP, TCP_NODELAY, (char*)&opt, sizeof(opt));
280                        }
281                        //------------------------------------------------------------------------------
282                        //
283                        // _setInformIfNewTCPIP()
284                        //
285                        //------------------------------------------------------------------------------
286                        inline void _setInformIfNewTCPIP(SocketHandle socket)
287                        {
288                        #ifdef PEGASUS_OS_ZOS
289                           // This function enables the notification of the CIM Server that a new
290 kumpf         1.26        // TCPIP transport layer is active. This is needed to be aware of a
291 thilo.boehm   1.25        // restart of the transport layer. When this option is in effect,
292                           // the accetp(), select(), and read() request will receive an errno=EIO.
293                           // Once this happens, the socket should be closed and create a new.
294 kumpf         1.26     
295 thilo.boehm   1.25        int NewTcpipOn = 1;
296 kumpf         1.26        setibmsockopt(
297                               socket,
298                               SOL_SOCKET,
299                               SO_EioIfNewTP,
300                               (char*)&NewTcpipOn,
301                               sizeof(NewTcpipOn));
302 thilo.boehm   1.25     #endif
303                        }
304                        
305                        
306                        SocketHandle Socket::createSocket(int domain, int type, int protocol)
307                        {
308                            SocketHandle newSocket;
309                        
310 kumpf         1.26         if (domain == AF_UNIX)
311 thilo.boehm   1.25         {
312 kumpf         1.26             return socket(domain,type,protocol);
313 thilo.boehm   1.25         }
314                        
315                            bool sendTcpipMsg = true;
316                        
317 kumpf         1.26         while (1)
318 thilo.boehm   1.25         {
319                                newSocket = socket(domain,type,protocol);
320                        
321 kumpf         1.27             if ((newSocket != PEGASUS_INVALID_SOCKET) ||
322                                    (getSocketError() != PEGASUS_NETWORK_TRYAGAIN))
323                                {
324                                    break;
325                                }
326                        
327                        #ifdef PEGASUS_OS_ZOS
328 thilo.boehm   1.25             // The program should wait for transport layer to become ready.
329                        
330 kumpf         1.27             if (sendTcpipMsg)
331 thilo.boehm   1.25             {
332 kumpf         1.27                 Logger::put_l(
333                                        Logger::STANDARD_LOG, System::CIMSERVER, Logger::INFORMATION,
334                                        "Common.Socket.WAIT_FOR_TCPIP",
335                                        "TCP/IP temporary unavailable.");
336                                    sendTcpipMsg = false;
337                                }
338 thilo.boehm   1.25     
339 kumpf         1.27             System::sleep(30);
340                        #endif
341 thilo.boehm   1.25         } // wait for the transport layer become ready.
342                        
343                            // Is the socket in an unrecoverable error ?
344                            if (newSocket == PEGASUS_INVALID_SOCKET)
345                            {
346                                // return immediate
347 kumpf         1.26             return PEGASUS_INVALID_SOCKET;
348                            }
349                            else
350                            {
351 thilo.boehm   1.25             // set aditional socket options
352                                _setTCPNoDelay(newSocket);
353                                _setInformIfNewTCPIP(newSocket);
354                        
355 kumpf         1.26             return newSocket;
356 thilo.boehm   1.25         }
357                        }
358                        
359 mike          1.2      PEGASUS_NAMESPACE_END

No CVS admin address has been configured
Powered by
ViewCVS 0.9.2