(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            // Author: Mike Brasher (mbrasher@bmc.com)
 33            //
 34 joyce.j 1.19 // Modified By: Josephine Eskaline Joyce, IBM (jojustin@in.ibm.com) for Bug#2513
 35 david.dillard 1.20 //              David Dillard, Symantec Corp.,  (david_dillard@symantec.com)
 36 mike          1.2  //
 37                    //%/////////////////////////////////////////////////////////////////////////////
 38                    
 39 kumpf         1.22.2.2 // NOCHKSRC
 40                        
 41 mike          1.2      #include "Socket.h"
 42                        
 43                        #ifdef PEGASUS_OS_TYPE_WINDOWS
 44 tony          1.9      #include <windows.h>
 45                        # ifndef _WINSOCKAPI_
 46                        #   include <winsock2.h>
 47                        # endif
 48 mike          1.2      #else
 49                        # include <cctype>
 50 chuck         1.5      #ifndef PEGASUS_OS_OS400
 51                        #   include <unistd.h>
 52                        #else
 53                        #   include <unistd.cleinc>
 54                        #endif
 55 marek         1.7      #   include <string.h>  // added by rk for memcpy
 56 mike          1.2      # include <cstdlib>
 57                        # include <errno.h>
 58                        # include <fcntl.h>
 59                        # include <netdb.h>
 60                        # include <netinet/in.h>
 61                        # include <arpa/inet.h>
 62                        # include <sys/socket.h>
 63 mday          1.11     # include <errno.h>
 64 mike          1.2      #endif
 65                        
 66 mday          1.11     #include <Pegasus/Common/Sharable.h>
 67 kumpf         1.22.2.2 #include <Pegasus/Common/Tracer.h>
 68 marek         1.22.2.1 
 69                        //------------------------------------------------------------------------------
 70                        //
 71                        // PEGASUS_RETRY_SYSTEM_CALL()
 72                        //
 73                        //     This macro repeats the given system call until it returns something
 74                        //     other than EINTR.
 75                        //
 76                        //------------------------------------------------------------------------------
 77                        
 78                        #ifdef PEGASUS_OS_TYPE_WINDOWS
 79                        #   define PEGASUS_RETRY_SYSTEM_CALL(EXPR, RESULT) RESULT = EXPR
 80                        #else
 81                        #   define PEGASUS_RETRY_SYSTEM_CALL(EXPR, RESULT) \
 82                                while (((RESULT = (EXPR)) == -1) && (errno == EINTR))
 83                        #endif
 84                        
 85                        //------------------------------------------------------------------------------
 86                        //
 87                        // PEGASUS_SOCKET_ERROR
 88                        //
 89 marek         1.22.2.1 //    This macro defines the error return code of network functions.
 90                        //    Should be used instead of comparing with -1.
 91                        //
 92                        //------------------------------------------------------------------------------
 93                        
 94                        #ifdef PEGASUS_OS_TYPE_WINDOWS
 95                        #   define PEGASUS_SOCKET_ERROR SOCKET_ERROR
 96                        #else
 97                        #   define PEGASUS_SOCKET_ERROR (-1)
 98                        #endif
 99                        
100 kumpf         1.22.2.2 //------------------------------------------------------------------------------
101                        //
102                        // getSocketError()
103                        //
104                        //------------------------------------------------------------------------------
105                        
106                        static inline int getSocketError()
107                        {
108                        #ifdef PEGASUS_OS_TYPE_WINDOWS
109                            return WSAGetLastError();
110                        #else
111                            return errno;
112                        #endif
113                        }
114                        
115                        //------------------------------------------------------------------------------
116                        //
117                        // PEGASUS_NETWORK_EINPROGRESS
118                        //
119                        // This return code indicates that the network function
120                        // is in progress. The application should try select or poll and
121 kumpf         1.22.2.2 // check for successful completion.
122                        //
123                        //------------------------------------------------------------------------------
124                        
125                        #if !defined(PEGASUS_OS_TYPE_WINDOWS)
126                        #   define PEGASUS_NETWORK_EINPROGRESS EINPROGRESS
127                        #else
128                        #   define PEGASUS_NETWORK_EINPROGRESS WSAEWOULDBLOCK
129                        #endif
130                        
131 marek         1.22.2.1 
132 mike          1.2      PEGASUS_NAMESPACE_BEGIN
133                        
134                        static Uint32 _socketInterfaceRefCount = 0;
135                        
136 kumpf         1.22.2.2 Boolean Socket::timedConnect(
137                            PEGASUS_SOCKET socket,
138                            sockaddr* address,
139                            int addressLength,
140                            Uint32 timeoutMilliseconds)
141                        {
142                            int connectResult;
143                            PEGASUS_RETRY_SYSTEM_CALL(
144                                ::connect(socket, address, addressLength), connectResult);
145                        
146                            if (connectResult == 0)
147                            {
148                                return true;
149                            }
150                        
151                            if (getSocketError() == PEGASUS_NETWORK_EINPROGRESS)
152                            {
153                                PEG_TRACE((TRC_HTTP, Tracer::LEVEL4,
154                                    "Connection to server in progress.  Waiting up to %u milliseconds "
155                                        "for the socket to become connected.",
156                                    timeoutMilliseconds));
157 kumpf         1.22.2.2 
158                                fd_set fdwrite;
159                                FD_ZERO(&fdwrite);
160                                FD_SET(socket, &fdwrite);
161                                struct timeval timeoutValue =
162                                    { timeoutMilliseconds/1000, timeoutMilliseconds%1000*1000 };
163                                int selectResult = -1;
164                        
165                                PEGASUS_RETRY_SYSTEM_CALL(
166                                    select(FD_SETSIZE, NULL, &fdwrite, NULL, &timeoutValue),
167                                    selectResult);
168                                if (selectResult == 0)
169                                {
170                                    PEG_TRACE_STRING(TRC_HTTP, Tracer::LEVEL2,
171                                        "select() timed out waiting for the socket connection to be "
172                                            "established.");
173                                    return false;
174                                }
175                                else if (selectResult > 0)
176                                {
177                                    int optval;
178 kumpf         1.22.2.2             PEGASUS_SOCKLEN_T optlen = sizeof(int);
179                                    getsockopt(socket, SOL_SOCKET, SO_ERROR, (char*)&optval, &optlen);
180                                    if (optval == 0)
181                                    {
182                                        PEG_TRACE_STRING(TRC_HTTP, Tracer::LEVEL4,
183                                            "Connection with server established.");
184                                        return true;
185                                    }
186                                    else
187                                    {
188                                        PEG_TRACE((TRC_HTTP, Tracer::LEVEL2,
189                                            "Did not connect, getsockopt() returned optval = %d",
190                                            optval));
191                                        return false;
192                                    }
193                                }
194                                else
195                                {
196                                    PEG_TRACE((TRC_HTTP, Tracer::LEVEL2,
197                                        "select() returned error code %d",
198                                        getSocketError()));
199 kumpf         1.22.2.2             return false;
200                                }
201                            }
202                        
203                            PEG_TRACE((TRC_HTTP, Tracer::LEVEL2,
204                                "connect() returned error code %d",
205                                getSocketError()));
206                            return false;
207                        }
208                        
209 david.dillard 1.20     Sint32 Socket::read(PEGASUS_SOCKET socket, void* ptr, Uint32 size)
210 mike          1.2      {
211                        #ifdef PEGASUS_OS_TYPE_WINDOWS
212                            return ::recv(socket, (char*)ptr, size, 0);
213                        #else
214 konrad.r      1.16     #if defined (__GNUC__) && !defined(PEGASUS_OS_SOLARIS) && !defined(PEGASUS_OS_DARWIN) && !defined(PEGASUS_OS_LSB)
215 mday          1.11         int ccode = TEMP_FAILURE_RETRY(::read(socket, (char*)ptr, size));
216                            return ccode;
217 david.dillard 1.20     #else
218 mike          1.2          return ::read(socket, (char*)ptr, size);
219                        #endif
220 mday          1.11     #endif
221 mike          1.2      }
222                        
223 david.dillard 1.20     Sint32 Socket::write(PEGASUS_SOCKET socket, const void* ptr, Uint32 size)
224 mike          1.2      {
225                        #ifdef PEGASUS_OS_TYPE_WINDOWS
226                            return ::send(socket, (const char*)ptr, size, 0);
227                        #else
228 konrad.r      1.16     #if (__GNUC__) && !defined(PEGASUS_OS_SOLARIS) && !defined(PEGASUS_OS_DARWIN) && !defined(PEGASUS_OS_LSB)
229 mday          1.11         int ccode = TEMP_FAILURE_RETRY(::write(socket, (char*)ptr, size));
230                            return ccode;
231                        #else
232 mike          1.2          return ::write(socket, (char*)ptr, size);
233                        #endif
234 mday          1.11     #endif
235 mike          1.2      }
236                        
237 marek         1.22.2.1 Sint32 Socket::timedWrite(PEGASUS_SOCKET socket, 
238                                                  const void* ptr, 
239                                                  Uint32 size, 
240                                                  Uint32 socketWriteTimeout)
241                        {
242                            Sint32 bytesWritten = 0;
243                            Sint32 totalBytesWritten = 0;
244                            Boolean socketTimedOut = false;
245                            int selreturn = 0;
246                            while (1)
247                            {
248                        #ifdef PEGASUS_OS_TYPE_WINDOWS
249                                PEGASUS_RETRY_SYSTEM_CALL(
250                                    ::send(socket, (const char*)ptr, size, 0), bytesWritten);
251                        #else
252                                PEGASUS_RETRY_SYSTEM_CALL(
253                                    ::write(socket, (char*)ptr, size), bytesWritten);
254                        #endif
255                                // Some data written this cycle ? 
256                                // Add it to the total amount of written data.
257                                if (bytesWritten > 0)
258 marek         1.22.2.1         {
259                                    totalBytesWritten += bytesWritten;
260                                    socketTimedOut = false;
261                                }
262                        
263                                // All data written ? return amount of data written
264                                if ((Uint32)bytesWritten == size)
265                                {
266                                    return totalBytesWritten;
267                                }
268                                // If data has been written partially, we resume writing data
269                                // this also accounts for the case of a signal interrupt
270                                // (i.e. errno = EINTR)
271                                if (bytesWritten > 0)
272                                {
273                                    size -= bytesWritten;
274                                    ptr = (void *)((char *)ptr + bytesWritten);
275                                    continue;
276                                }
277                                // Something went wrong
278                                if (bytesWritten == PEGASUS_SOCKET_ERROR)
279 marek         1.22.2.1         {
280                                    // if we already waited for the socket to get ready, bail out
281                                    if( socketTimedOut ) return bytesWritten;
282                        #ifdef PEGASUS_OS_TYPE_WINDOWS
283                                    if (WSAGetLastError() == WSAEWOULDBLOCK)
284                        #else
285                                    if (errno == EAGAIN || errno == EWOULDBLOCK)
286                        #endif
287                                    {
288                                        fd_set fdwrite;
289                                         // max. timeout seconds waiting for the socket to get ready
290                                        struct timeval tv = { socketWriteTimeout, 0 };
291                                        FD_ZERO(&fdwrite);
292                                        FD_SET(socket, &fdwrite);
293                                        selreturn = select(FD_SETSIZE, NULL, &fdwrite, NULL, &tv);
294                                        if (selreturn == 0) socketTimedOut = true; // ran out of time
295                                        continue;            
296                                    }
297                                    return bytesWritten;
298                                }
299                            }
300 marek         1.22.2.1 }
301                        
302 david.dillard 1.20     void Socket::close(PEGASUS_SOCKET socket)
303 mike          1.2      {
304 joyce.j       1.19       if(-1 != socket)
305                           {
306                            #ifdef PEGASUS_OS_TYPE_WINDOWS
307                            if(!closesocket(socket)) socket=-1;
308                            #else
309                            #if (__GNUC__) && !defined(PEGASUS_OS_SOLARIS) && !defined(PEGASUS_OS_DARWIN) && !defined(PEGASUS_OS_LSB)
310                               if(!TEMP_FAILURE_RETRY(::close(socket))) socket = -1;
311                            #else
312                               if(!::close(socket)) socket = -1;
313                            #endif
314                            #endif
315                           }
316 mike          1.2      }
317                        
318 david.dillard 1.20     void Socket::disableBlocking(PEGASUS_SOCKET socket)
319 mike          1.2      {
320                        #ifdef PEGASUS_OS_TYPE_WINDOWS
321 kumpf         1.22.2.2     unsigned long flag = 1;    // Use "flag = 0" to enable blocking
322 mike          1.2          ioctlsocket(socket, FIONBIO, &flag);
323                        #else
324                            int flags = fcntl(socket, F_GETFL, 0);
325 kumpf         1.22.2.2     flags |= O_NONBLOCK;    // Use "flags &= ~O_NONBLOCK" to enable blocking
326 mike          1.2          fcntl(socket, F_SETFL, flags);
327                        #endif
328                        }
329                        
330                        void Socket::initializeInterface()
331                        {
332                        #ifdef PEGASUS_OS_TYPE_WINDOWS
333                            if (_socketInterfaceRefCount == 0)
334                            {
335 david.dillard 1.20             WSADATA tmp;
336 mike          1.2      
337 david.dillard 1.20         if (WSAStartup(0x202, &tmp) == SOCKET_ERROR)
338                                WSACleanup();
339 mike          1.2          }
340                        
341                            _socketInterfaceRefCount++;
342                        #endif
343                        }
344                        
345                        void Socket::uninitializeInterface()
346                        {
347                        #ifdef PEGASUS_OS_TYPE_WINDOWS
348                            _socketInterfaceRefCount--;
349                        
350                            if (_socketInterfaceRefCount == 0)
351 david.dillard 1.20             WSACleanup();
352 mike          1.2      #endif
353                        }
354                        
355 mday          1.11     
356 mike          1.2      PEGASUS_NAMESPACE_END
357 mday          1.11     

No CVS admin address has been configured
Powered by
ViewCVS 0.9.2