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
|