(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 mike        1.23 
 42                  //------------------------------------------------------------------------------
 43                  //
 44                  // PEGASUS_RETRY_SYSTEM_CALL()
 45                  //
 46                  //     This macro repeats the given system call until it returns something
 47                  //     other than EINTR.
 48                  //
 49                  //------------------------------------------------------------------------------
 50 mike        1.2  
 51                  #ifdef PEGASUS_OS_TYPE_WINDOWS
 52 mike        1.23 #   define PEGASUS_RETRY_SYSTEM_CALL(EXPR, RESULT) RESULT = EXPR
 53                  #else
 54                  #   define PEGASUS_RETRY_SYSTEM_CALL(EXPR, RESULT) \
 55                          while (((RESULT = (EXPR)) == -1) && (errno == EINTR))
 56 mike        1.2  #endif
 57                  
 58                  PEGASUS_NAMESPACE_BEGIN
 59                  
 60                  static Uint32 _socketInterfaceRefCount = 0;
 61                  
 62 mike        1.23 Sint32 Socket::read(SocketHandle socket, void* ptr, Uint32 size)
 63 mike        1.2  {
 64                  #ifdef PEGASUS_OS_TYPE_WINDOWS
 65                      return ::recv(socket, (char*)ptr, size, 0);
 66                  #else
 67 mike        1.23     int status;
 68                      PEGASUS_RETRY_SYSTEM_CALL(::read(socket, (char*)ptr, size), status);
 69                      return status;
 70 mday        1.11 #endif
 71 mike        1.2  }
 72                  
 73 mike        1.23 Sint32 Socket::write(SocketHandle socket, const void* ptr, Uint32 size)
 74 mike        1.2  {
 75                  #ifdef PEGASUS_OS_TYPE_WINDOWS
 76                      return ::send(socket, (const char*)ptr, size, 0);
 77                  #else
 78 mike        1.23     int status;
 79                      PEGASUS_RETRY_SYSTEM_CALL(::write(socket, (char*)ptr, size), status);
 80                      return status;
 81 mday        1.11 #endif
 82 mike        1.2  }
 83                  
 84 kumpf       1.26 Sint32 Socket::timedWrite(
 85                      SocketHandle socket,
 86                      const void* ptr,
 87                      Uint32 size,
 88                      Uint32 socketWriteTimeout)
 89 marek       1.24 {
 90                      Sint32 bytesWritten = 0;
 91                      Sint32 totalBytesWritten = 0;
 92                      Boolean socketTimedOut = false;
 93                      int selreturn = 0;
 94                      while (1)
 95                      {
 96                  #ifdef PEGASUS_OS_TYPE_WINDOWS
 97                          PEGASUS_RETRY_SYSTEM_CALL(
 98                              ::send(socket, (const char*)ptr, size, 0), bytesWritten);
 99                  #else
100                          PEGASUS_RETRY_SYSTEM_CALL(
101                              ::write(socket, (char*)ptr, size), bytesWritten);
102                  #endif
103 kumpf       1.26         // Some data written this cycle ?
104 marek       1.24         // Add it to the total amount of written data.
105                          if (bytesWritten > 0)
106                          {
107                              totalBytesWritten += bytesWritten;
108                              socketTimedOut = false;
109                          }
110                  
111                          // All data written ? return amount of data written
112                          if ((Uint32)bytesWritten == size)
113                          {
114                              return totalBytesWritten;
115                          }
116                          // If data has been written partially, we resume writing data
117                          // this also accounts for the case of a signal interrupt
118                          // (i.e. errno = EINTR)
119                          if (bytesWritten > 0)
120                          {
121                              size -= bytesWritten;
122                              ptr = (void *)((char *)ptr + bytesWritten);
123                              continue;
124                          }
125 marek       1.24         // Something went wrong
126                          if (bytesWritten == PEGASUS_SOCKET_ERROR)
127                          {
128                              // if we already waited for the socket to get ready, bail out
129 kumpf       1.26             if (socketTimedOut) return bytesWritten;
130 marek       1.24 #ifdef PEGASUS_OS_TYPE_WINDOWS
131                              if (WSAGetLastError() == WSAEWOULDBLOCK)
132                  #else
133                              if (errno == EAGAIN || errno == EWOULDBLOCK)
134                  #endif
135                              {
136                                  fd_set fdwrite;
137                                   // max. timeout seconds waiting for the socket to get ready
138                                  struct timeval tv = { socketWriteTimeout, 0 };
139                                  FD_ZERO(&fdwrite);
140                                  FD_SET(socket, &fdwrite);
141                                  selreturn = select(FD_SETSIZE, NULL, &fdwrite, NULL, &tv);
142                                  if (selreturn == 0) socketTimedOut = true; // ran out of time
143 kumpf       1.26                 continue;
144 marek       1.24             }
145                              return bytesWritten;
146                          }
147                      }
148                  }
149                  
150 mike        1.23 void Socket::close(SocketHandle socket)
151 mike        1.2  {
152 mike        1.23     if (socket != -1)
153                      {
154                  #ifdef PEGASUS_OS_TYPE_WINDOWS
155 kumpf       1.26         if (!closesocket(socket))
156                              socket = -1;
157 mike        1.23 #else
158 kumpf       1.26         int status;
159                          PEGASUS_RETRY_SYSTEM_CALL(::close(socket), status);
160 mike        1.23 
161 kumpf       1.26         if (status == 0)
162                              socket = -1;
163 mike        1.23 #endif
164                      }
165 mike        1.2  }
166                  
167 mike        1.23 void Socket::enableBlocking(SocketHandle socket)
168 mike        1.2  {
169                  #ifdef PEGASUS_OS_TYPE_WINDOWS
170                      unsigned long flag = 0;
171                      ioctlsocket(socket, FIONBIO, &flag);
172                  #else
173                      int flags = fcntl(socket, F_GETFL, 0);
174                      flags &= ~O_NONBLOCK;
175                      fcntl(socket, F_SETFL, flags);
176                  #endif
177                  }
178                  
179 mike        1.23 void Socket::disableBlocking(SocketHandle socket)
180 mike        1.2  {
181                  #ifdef PEGASUS_OS_TYPE_WINDOWS
182                      unsigned long flag = 1;
183                      ioctlsocket(socket, FIONBIO, &flag);
184                  #else
185                      int flags = fcntl(socket, F_GETFL, 0);
186                      flags |= O_NONBLOCK;
187                      fcntl(socket, F_SETFL, flags);
188                  #endif
189                  }
190                  
191                  void Socket::initializeInterface()
192                  {
193                  #ifdef PEGASUS_OS_TYPE_WINDOWS
194                      if (_socketInterfaceRefCount == 0)
195                      {
196 david.dillard 1.20         WSADATA tmp;
197 mike          1.2  
198 kumpf         1.26         if (WSAStartup(0x202, &tmp) == SOCKET_ERROR)
199                                WSACleanup();
200 mike          1.2      }
201                    
202                        _socketInterfaceRefCount++;
203                    #endif
204                    }
205                    
206                    void Socket::uninitializeInterface()
207                    {
208                    #ifdef PEGASUS_OS_TYPE_WINDOWS
209                        _socketInterfaceRefCount--;
210                    
211                        if (_socketInterfaceRefCount == 0)
212 david.dillard 1.20         WSACleanup();
213 mike          1.2  #endif
214                    }
215                    
216 thilo.boehm   1.25 //------------------------------------------------------------------------------
217                    //
218                    // _setTCPNoDelay()
219                    //
220                    //------------------------------------------------------------------------------
221                    
222                    inline void _setTCPNoDelay(SocketHandle socket)
223                    {
224                        // This function disables "Nagle's Algorithm" also known as "the TCP delay
225                        // algorithm", which causes read operations to obtain whatever data is
226 kumpf         1.26     // already in the input queue and then wait a little longer to see if
227                        // more data arrives. This algorithm optimizes the case in which data is
228                        // sent in only one direction but severely impairs performance of round
229                        // trip servers. Disabling TCP delay is a standard technique for round
230 thilo.boehm   1.25     // trip servers.
231                    
232                       int opt = 1;
233                       setsockopt(socket, IPPROTO_TCP, TCP_NODELAY, (char*)&opt, sizeof(opt));
234                    }
235                    //------------------------------------------------------------------------------
236                    //
237                    // _setInformIfNewTCPIP()
238                    //
239                    //------------------------------------------------------------------------------
240                    inline void _setInformIfNewTCPIP(SocketHandle socket)
241                    {
242                    #ifdef PEGASUS_OS_ZOS
243                       // This function enables the notification of the CIM Server that a new
244 kumpf         1.26    // TCPIP transport layer is active. This is needed to be aware of a
245 thilo.boehm   1.25    // restart of the transport layer. When this option is in effect,
246                       // the accetp(), select(), and read() request will receive an errno=EIO.
247                       // Once this happens, the socket should be closed and create a new.
248 kumpf         1.26 
249 thilo.boehm   1.25    int NewTcpipOn = 1;
250 kumpf         1.26    setibmsockopt(
251                           socket,
252                           SOL_SOCKET,
253                           SO_EioIfNewTP,
254                           (char*)&NewTcpipOn,
255                           sizeof(NewTcpipOn));
256 thilo.boehm   1.25 #endif
257                    }
258                    
259                    
260                    SocketHandle Socket::createSocket(int domain, int type, int protocol)
261                    {
262                        SocketHandle newSocket;
263                    
264 kumpf         1.26     if (domain == AF_UNIX)
265 thilo.boehm   1.25     {
266 kumpf         1.26         return socket(domain,type,protocol);
267 thilo.boehm   1.25     }
268                    
269                        bool sendTcpipMsg = true;
270                    
271 kumpf         1.26     while (1)
272 thilo.boehm   1.25     {
273                            newSocket = socket(domain,type,protocol);
274                    
275                            // The program should wait for transport layer to become ready.
276                    
277 kumpf         1.26         if (newSocket == PEGASUS_INVALID_SOCKET &&
278 thilo.boehm   1.25            getSocketError() == PEGASUS_NETWORK_TCPIP_TRYAGAIN )
279                            {
280 kumpf         1.26            if (sendTcpipMsg)
281 thilo.boehm   1.25            {
282 kumpf         1.26                Logger::put_l(
283                                       Logger::STANDARD_LOG, System::CIMSERVER, Logger::INFORMATION,
284                                       "Common.Socket.WAIT_FOR_TCPIP",
285                                       "TCP/IP temporary unavailable.");
286 thilo.boehm   1.25                sendTcpipMsg=false;
287                               }
288                    
289                               System::sleep(30);
290                               continue;
291 kumpf         1.26         }
292                            else
293 thilo.boehm   1.25         {
294                               break;
295                            }
296                        } // wait for the transport layer become ready.
297                    
298                        // Is the socket in an unrecoverable error ?
299                        if (newSocket == PEGASUS_INVALID_SOCKET)
300                        {
301                            // return immediate
302 kumpf         1.26         return PEGASUS_INVALID_SOCKET;
303                        }
304                        else
305                        {
306 thilo.boehm   1.25         // set aditional socket options
307                            _setTCPNoDelay(newSocket);
308                            _setInformIfNewTCPIP(newSocket);
309                    
310 kumpf         1.26         return newSocket;
311 thilo.boehm   1.25     }
312                    }
313                    
314 mike          1.2  PEGASUS_NAMESPACE_END

No CVS admin address has been configured
Powered by
ViewCVS 0.9.2