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

No CVS admin address has been configured
Powered by
ViewCVS 0.9.2