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

  1 martin 1.36 //%LICENSE////////////////////////////////////////////////////////////////
  2 martin 1.37 //
  3 martin 1.36 // Licensed to The Open Group (TOG) under one or more contributor license
  4             // agreements.  Refer to the OpenPegasusNOTICE.txt file distributed with
  5             // this work for additional information regarding copyright ownership.
  6             // Each contributor licenses this file to you under the OpenPegasus Open
  7             // Source License; you may not use this file except in compliance with the
  8             // License.
  9 martin 1.37 //
 10 martin 1.36 // Permission is hereby granted, free of charge, to any person obtaining a
 11             // copy of this software and associated documentation files (the "Software"),
 12             // to deal in the Software without restriction, including without limitation
 13             // the rights to use, copy, modify, merge, publish, distribute, sublicense,
 14             // and/or sell copies of the Software, and to permit persons to whom the
 15             // Software is furnished to do so, subject to the following conditions:
 16 martin 1.37 //
 17 martin 1.36 // The above copyright notice and this permission notice shall be included
 18             // in all copies or substantial portions of the Software.
 19 martin 1.37 //
 20 martin 1.36 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
 21 martin 1.37 // OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
 22 martin 1.36 // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
 23             // IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
 24             // CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
 25             // TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
 26             // SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
 27 martin 1.37 //
 28 martin 1.36 //////////////////////////////////////////////////////////////////////////
 29 mike   1.2  //
 30             //%/////////////////////////////////////////////////////////////////////////////
 31             
 32             #include "Socket.h"
 33 mike   1.23 #include "Network.h"
 34             #include <cctype>
 35             #include <cstring>
 36             #include <Pegasus/Common/Sharable.h>
 37 thilo.boehm 1.25 #include <Pegasus/Common/Logger.h>
 38                  #include <Pegasus/Common/System.h>
 39 kumpf       1.28 #include <Pegasus/Common/Tracer.h>
 40 kumpf       1.35 #include <Pegasus/Common/Threads.h>
 41 venkat.puvvada 1.38 #include <Pegasus/Common/Mutex.h>
 42 mike           1.23 
 43 kumpf          1.28 PEGASUS_NAMESPACE_BEGIN
 44                     
 45 venkat.puvvada 1.38 #ifdef PEGASUS_OS_TYPE_WINDOWS
 46 kumpf          1.28 static Uint32 _socketInterfaceRefCount = 0;
 47 venkat.puvvada 1.38 static Mutex _socketInterfaceRefCountLock;
 48                     #endif
 49 kumpf          1.28 
 50                     Boolean Socket::timedConnect(
 51                         SocketHandle socket,
 52                         sockaddr* address,
 53                         int addressLength,
 54                         Uint32 timeoutMilliseconds)
 55                     {
 56                         int connectResult;
 57 kumpf          1.35 #ifdef PEGASUS_OS_TYPE_WINDOWS
 58                         connectResult = ::connect(socket, address, addressLength);
 59                     #else
 60                         Boolean connectionAlreadyRefused = false;
 61                         Uint32 maxConnectAttempts = 100;
 62                         // Retry the connect() until it succeeds or it fails with an error other
 63                         // than EINTR, EAGAIN (for Linux), or the first ECONNREFUSED (for HP-UX).
 64                         while (((connectResult = ::connect(socket, address, addressLength)) == -1)
 65                                && (maxConnectAttempts-- > 0)
 66                                && ((errno == EINTR) || (errno == EAGAIN) ||
 67                                    ((errno == ECONNREFUSED) && !connectionAlreadyRefused)))
 68                         {
 69                             if (errno == ECONNREFUSED)
 70                             {
 71                                 connectionAlreadyRefused = true;
 72                             }
 73                             Threads::sleep(1);
 74                         }
 75                     #endif
 76 kumpf          1.28 
 77                         if (connectResult == 0)
 78                         {
 79                             return true;
 80                         }
 81 mike           1.2  
 82 kumpf          1.28     if (getSocketError() == PEGASUS_NETWORK_EINPROGRESS)
 83                         {
 84                             PEG_TRACE((TRC_HTTP, Tracer::LEVEL4,
 85                                 "Connection to server in progress.  Waiting up to %u milliseconds "
 86                                     "for the socket to become connected.",
 87                                 timeoutMilliseconds));
 88                     
 89                             fd_set fdwrite;
 90                             FD_ZERO(&fdwrite);
 91                             FD_SET(socket, &fdwrite);
 92                             struct timeval timeoutValue =
 93                                 { timeoutMilliseconds/1000, timeoutMilliseconds%1000*1000 };
 94                             int selectResult = -1;
 95 mike           1.2  
 96 venkat.puvvada 1.34 #ifdef PEGASUS_OS_TYPE_WINDOWS
 97                             PEGASUS_RETRY_SYSTEM_CALL(
 98                                 select(FD_SETSIZE, NULL, &fdwrite, &fdwrite, &timeoutValue),
 99                                 selectResult);
100                     #else
101 kumpf          1.28         PEGASUS_RETRY_SYSTEM_CALL(
102                                 select(FD_SETSIZE, NULL, &fdwrite, NULL, &timeoutValue),
103                                 selectResult);
104 venkat.puvvada 1.34 #endif
105 kumpf          1.28         if (selectResult == 0)
106                             {
107 marek          1.32             PEG_TRACE_CSTRING(TRC_HTTP, Tracer::LEVEL1,
108 kumpf          1.28                 "select() timed out waiting for the socket connection to be "
109                                         "established.");
110                                 return false;
111                             }
112                             else if (selectResult > 0)
113                             {
114                                 int optval;
115                                 SocketLength optlen = sizeof(int);
116                                 getsockopt(socket, SOL_SOCKET, SO_ERROR, (char*)&optval, &optlen);
117                                 if (optval == 0)
118                                 {
119                                     PEG_TRACE_CSTRING(TRC_HTTP, Tracer::LEVEL4,
120                                         "Connection with server established.");
121                                     return true;
122                                 }
123                                 else
124                                 {
125 marek          1.32                 PEG_TRACE((TRC_HTTP, Tracer::LEVEL1,
126 kumpf          1.28                     "Did not connect, getsockopt() returned optval = %d",
127                                         optval));
128                                     return false;
129                                 }
130                             }
131                             else
132                             {
133 marek          1.32             PEG_TRACE((TRC_HTTP, Tracer::LEVEL1,
134 kumpf          1.28                 "select() returned error code %d",
135                                     getSocketError()));
136                                 return false;
137                             }
138                         }
139 mike           1.2  
140 marek          1.32     PEG_TRACE((TRC_HTTP, Tracer::LEVEL1,
141 kumpf          1.28         "connect() returned error code %d",
142                             getSocketError()));
143                         return false;
144                     }
145 mike           1.2  
146 mike           1.23 Sint32 Socket::read(SocketHandle socket, void* ptr, Uint32 size)
147 mike           1.2  {
148                     #ifdef PEGASUS_OS_TYPE_WINDOWS
149                         return ::recv(socket, (char*)ptr, size, 0);
150                     #else
151 mike           1.23     int status;
152                         PEGASUS_RETRY_SYSTEM_CALL(::read(socket, (char*)ptr, size), status);
153                         return status;
154 mday           1.11 #endif
155 mike           1.2  }
156                     
157 mike           1.23 Sint32 Socket::write(SocketHandle socket, const void* ptr, Uint32 size)
158 mike           1.2  {
159                     #ifdef PEGASUS_OS_TYPE_WINDOWS
160                         return ::send(socket, (const char*)ptr, size, 0);
161                     #else
162 mike           1.23     int status;
163                         PEGASUS_RETRY_SYSTEM_CALL(::write(socket, (char*)ptr, size), status);
164                         return status;
165 mday           1.11 #endif
166 mike           1.2  }
167                     
168 kumpf          1.26 Sint32 Socket::timedWrite(
169                         SocketHandle socket,
170                         const void* ptr,
171                         Uint32 size,
172                         Uint32 socketWriteTimeout)
173 marek          1.24 {
174                         Sint32 bytesWritten = 0;
175                         Sint32 totalBytesWritten = 0;
176                         Boolean socketTimedOut = false;
177                         int selreturn = 0;
178                         while (1)
179                         {
180                     #ifdef PEGASUS_OS_TYPE_WINDOWS
181                             PEGASUS_RETRY_SYSTEM_CALL(
182                                 ::send(socket, (const char*)ptr, size, 0), bytesWritten);
183                     #else
184                             PEGASUS_RETRY_SYSTEM_CALL(
185                                 ::write(socket, (char*)ptr, size), bytesWritten);
186                     #endif
187 kumpf          1.26         // Some data written this cycle ?
188 marek          1.24         // Add it to the total amount of written data.
189                             if (bytesWritten > 0)
190                             {
191                                 totalBytesWritten += bytesWritten;
192                                 socketTimedOut = false;
193                             }
194                     
195                             // All data written ? return amount of data written
196                             if ((Uint32)bytesWritten == size)
197                             {
198                                 return totalBytesWritten;
199                             }
200                             // If data has been written partially, we resume writing data
201                             // this also accounts for the case of a signal interrupt
202                             // (i.e. errno = EINTR)
203                             if (bytesWritten > 0)
204                             {
205                                 size -= bytesWritten;
206                                 ptr = (void *)((char *)ptr + bytesWritten);
207                                 continue;
208                             }
209 marek          1.24         // Something went wrong
210                             if (bytesWritten == PEGASUS_SOCKET_ERROR)
211                             {
212                                 // if we already waited for the socket to get ready, bail out
213 kumpf          1.26             if (socketTimedOut) return bytesWritten;
214 marek          1.24 #ifdef PEGASUS_OS_TYPE_WINDOWS
215                                 if (WSAGetLastError() == WSAEWOULDBLOCK)
216                     #else
217                                 if (errno == EAGAIN || errno == EWOULDBLOCK)
218                     #endif
219                                 {
220                                     fd_set fdwrite;
221                                      // max. timeout seconds waiting for the socket to get ready
222                                     struct timeval tv = { socketWriteTimeout, 0 };
223                                     FD_ZERO(&fdwrite);
224                                     FD_SET(socket, &fdwrite);
225                                     selreturn = select(FD_SETSIZE, NULL, &fdwrite, NULL, &tv);
226                                     if (selreturn == 0) socketTimedOut = true; // ran out of time
227 kumpf          1.26                 continue;
228 marek          1.24             }
229                                 return bytesWritten;
230                             }
231                         }
232                     }
233                     
234 kumpf          1.29 void Socket::close(SocketHandle& socket)
235 mike           1.2  {
236 kumpf          1.29     if (socket != PEGASUS_INVALID_SOCKET)
237 mike           1.23     {
238                     #ifdef PEGASUS_OS_TYPE_WINDOWS
239 kumpf          1.26         if (!closesocket(socket))
240 kumpf          1.29         {
241                                 socket = PEGASUS_INVALID_SOCKET;
242                             }
243 mike           1.23 #else
244 kumpf          1.26         int status;
245                             PEGASUS_RETRY_SYSTEM_CALL(::close(socket), status);
246 mike           1.23 
247 kumpf          1.26         if (status == 0)
248 kumpf          1.29         {
249                                 socket = PEGASUS_INVALID_SOCKET;
250                             }
251 mike           1.23 #endif
252                         }
253 mike           1.2  }
254                     
255 mike           1.23 void Socket::disableBlocking(SocketHandle socket)
256 mike           1.2  {
257                     #ifdef PEGASUS_OS_TYPE_WINDOWS
258 kumpf          1.28     unsigned long flag = 1;    // Use "flag = 0" to enable blocking
259 mike           1.2      ioctlsocket(socket, FIONBIO, &flag);
260 carson.hovey   1.31 #elif PEGASUS_OS_VMS
261                         int flag=1;                // Use "flag = 0" to enable blocking
262                         ioctl(socket, FIONBIO, &flag);
263 mike           1.2  #else
264                         int flags = fcntl(socket, F_GETFL, 0);
265 kumpf          1.28     flags |= O_NONBLOCK;    // Use "flags &= ~O_NONBLOCK" to enable blocking
266 mike           1.2      fcntl(socket, F_SETFL, flags);
267                     #endif
268                     }
269                     
270                     void Socket::initializeInterface()
271                     {
272                     #ifdef PEGASUS_OS_TYPE_WINDOWS
273 venkat.puvvada 1.38     AutoMutex mtx(_socketInterfaceRefCountLock);
274 mike           1.2      if (_socketInterfaceRefCount == 0)
275                         {
276 david.dillard  1.20         WSADATA tmp;
277 mike           1.2  
278 kumpf          1.30         int err = WSAStartup(0x202, &tmp);
279                             if (err != 0)
280                             {
281                                 throw Exception(MessageLoaderParms(
282                                     "Common.Socket.WSASTARTUP_FAILED.WINDOWS",
283                                     "WSAStartup failed with error $0.",
284                                     err));
285                             }
286 mike           1.2      }
287                     
288                         _socketInterfaceRefCount++;
289                     #endif
290                     }
291                     
292                     void Socket::uninitializeInterface()
293                     {
294                     #ifdef PEGASUS_OS_TYPE_WINDOWS
295 venkat.puvvada 1.38     AutoMutex mtx(_socketInterfaceRefCountLock);
296 mike           1.2      _socketInterfaceRefCount--;
297                     
298                         if (_socketInterfaceRefCount == 0)
299 david.dillard  1.20         WSACleanup();
300 mike           1.2  #endif
301                     }
302                     
303 thilo.boehm    1.25 //------------------------------------------------------------------------------
304                     //
305                     // _setTCPNoDelay()
306                     //
307                     //------------------------------------------------------------------------------
308                     
309                     inline void _setTCPNoDelay(SocketHandle socket)
310                     {
311                         // This function disables "Nagle's Algorithm" also known as "the TCP delay
312                         // algorithm", which causes read operations to obtain whatever data is
313 kumpf          1.26     // already in the input queue and then wait a little longer to see if
314                         // more data arrives. This algorithm optimizes the case in which data is
315                         // sent in only one direction but severely impairs performance of round
316                         // trip servers. Disabling TCP delay is a standard technique for round
317 thilo.boehm    1.25     // trip servers.
318                     
319                        int opt = 1;
320                        setsockopt(socket, IPPROTO_TCP, TCP_NODELAY, (char*)&opt, sizeof(opt));
321                     }
322                     //------------------------------------------------------------------------------
323                     //
324                     // _setInformIfNewTCPIP()
325                     //
326                     //------------------------------------------------------------------------------
327                     inline void _setInformIfNewTCPIP(SocketHandle socket)
328                     {
329                     #ifdef PEGASUS_OS_ZOS
330                        // This function enables the notification of the CIM Server that a new
331 kumpf          1.26    // TCPIP transport layer is active. This is needed to be aware of a
332 thilo.boehm    1.25    // restart of the transport layer. When this option is in effect,
333                        // the accetp(), select(), and read() request will receive an errno=EIO.
334                        // Once this happens, the socket should be closed and create a new.
335 kumpf          1.26 
336 thilo.boehm    1.25    int NewTcpipOn = 1;
337 kumpf          1.26    setibmsockopt(
338                            socket,
339                            SOL_SOCKET,
340                            SO_EioIfNewTP,
341                            (char*)&NewTcpipOn,
342                            sizeof(NewTcpipOn));
343 thilo.boehm    1.25 #endif
344                     }
345                     
346                     
347                     SocketHandle Socket::createSocket(int domain, int type, int protocol)
348                     {
349                         SocketHandle newSocket;
350                     
351 kumpf          1.26     if (domain == AF_UNIX)
352 thilo.boehm    1.25     {
353 kumpf          1.26         return socket(domain,type,protocol);
354 thilo.boehm    1.25     }
355                     
356                         bool sendTcpipMsg = true;
357                     
358 kumpf          1.26     while (1)
359 thilo.boehm    1.25     {
360                             newSocket = socket(domain,type,protocol);
361                     
362 kumpf          1.27         if ((newSocket != PEGASUS_INVALID_SOCKET) ||
363                                 (getSocketError() != PEGASUS_NETWORK_TRYAGAIN))
364                             {
365                                 break;
366                             }
367                     
368                     #ifdef PEGASUS_OS_ZOS
369 thilo.boehm    1.25         // The program should wait for transport layer to become ready.
370                     
371 kumpf          1.27         if (sendTcpipMsg)
372 thilo.boehm    1.25         {
373 kumpf          1.27             Logger::put_l(
374                                     Logger::STANDARD_LOG, System::CIMSERVER, Logger::INFORMATION,
375 kumpf          1.33                 MessageLoaderParms(
376                                         "Common.Socket.WAIT_FOR_TCPIP",
377                                         "TCP/IP temporary unavailable."));
378 kumpf          1.27             sendTcpipMsg = false;
379                             }
380 thilo.boehm    1.25 
381 kumpf          1.27         System::sleep(30);
382                     #endif
383 thilo.boehm    1.25     } // wait for the transport layer become ready.
384                     
385                         // Is the socket in an unrecoverable error ?
386                         if (newSocket == PEGASUS_INVALID_SOCKET)
387                         {
388                             // return immediate
389 kumpf          1.26         return PEGASUS_INVALID_SOCKET;
390                         }
391                         else
392                         {
393 thilo.boehm    1.25         // set aditional socket options
394                             _setTCPNoDelay(newSocket);
395                             _setInformIfNewTCPIP(newSocket);
396                     
397 kumpf          1.26         return newSocket;
398 thilo.boehm    1.25     }
399                     }
400                     
401 mike           1.2  PEGASUS_NAMESPACE_END

No CVS admin address has been configured
Powered by
ViewCVS 0.9.2