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