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.28 #include <Pegasus/Common/Tracer.h>
|
42 mike 1.23
|
43 kumpf 1.28 PEGASUS_NAMESPACE_BEGIN
44
45 static Uint32 _socketInterfaceRefCount = 0;
46
47 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 mike 1.2
|
62 kumpf 1.28 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
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 mike 1.2
|
76 kumpf 1.28 PEGASUS_RETRY_SYSTEM_CALL(
77 select(FD_SETSIZE, NULL, &fdwrite, NULL, &timeoutValue),
78 selectResult);
79 if (selectResult == 0)
80 {
|
81 mike 1.31.4.1 PEG_TRACE_CSTRING(TRC_HTTP, Tracer::LEVEL1,
|
82 kumpf 1.28 "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 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 mike 1.31.4.1 PEG_TRACE((TRC_HTTP, Tracer::LEVEL1,
|
100 kumpf 1.28 "Did not connect, getsockopt() returned optval = %d",
101 optval));
102 return false;
103 }
104 }
105 else
106 {
|
107 mike 1.31.4.1 PEG_TRACE((TRC_HTTP, Tracer::LEVEL1,
|
108 kumpf 1.28 "select() returned error code %d",
109 getSocketError()));
110 return false;
111 }
112 }
|
113 mike 1.2
|
114 mike 1.31.4.1 PEG_TRACE((TRC_HTTP, Tracer::LEVEL1,
|
115 kumpf 1.28 "connect() returned error code %d",
116 getSocketError()));
117 return false;
118 }
|
119 mike 1.2
|
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 kumpf 1.29 void Socket::close(SocketHandle& socket)
|
209 mike 1.2 {
|
210 kumpf 1.29 if (socket != PEGASUS_INVALID_SOCKET)
|
211 mike 1.23 {
212 #ifdef PEGASUS_OS_TYPE_WINDOWS
|
213 kumpf 1.26 if (!closesocket(socket))
|
214 kumpf 1.29 {
215 socket = PEGASUS_INVALID_SOCKET;
216 }
|
217 mike 1.23 #else
|
218 kumpf 1.26 int status;
219 PEGASUS_RETRY_SYSTEM_CALL(::close(socket), status);
|
220 mike 1.23
|
221 kumpf 1.26 if (status == 0)
|
222 kumpf 1.29 {
223 socket = PEGASUS_INVALID_SOCKET;
224 }
|
225 mike 1.23 #endif
226 }
|
227 mike 1.2 }
228
|
229 mike 1.23 void Socket::disableBlocking(SocketHandle socket)
|
230 mike 1.2 {
231 #ifdef PEGASUS_OS_TYPE_WINDOWS
|
232 kumpf 1.28 unsigned long flag = 1; // Use "flag = 0" to enable blocking
|
233 mike 1.2 ioctlsocket(socket, FIONBIO, &flag);
|
234 carson.hovey 1.31 #elif PEGASUS_OS_VMS
235 int flag=1; // Use "flag = 0" to enable blocking
236 ioctl(socket, FIONBIO, &flag);
|
237 mike 1.2 #else
238 int flags = fcntl(socket, F_GETFL, 0);
|
239 kumpf 1.28 flags |= O_NONBLOCK; // Use "flags &= ~O_NONBLOCK" to enable blocking
|
240 mike 1.2 fcntl(socket, F_SETFL, flags);
241 #endif
242 }
243
244 void Socket::initializeInterface()
245 {
246 #ifdef PEGASUS_OS_TYPE_WINDOWS
247 if (_socketInterfaceRefCount == 0)
248 {
|
249 david.dillard 1.20 WSADATA tmp;
|
250 mike 1.2
|
251 kumpf 1.30 int err = WSAStartup(0x202, &tmp);
252 if (err != 0)
253 {
254 throw Exception(MessageLoaderParms(
255 "Common.Socket.WSASTARTUP_FAILED.WINDOWS",
256 "WSAStartup failed with error $0.",
257 err));
258 }
|
259 mike 1.2 }
260
261 _socketInterfaceRefCount++;
262 #endif
263 }
264
265 void Socket::uninitializeInterface()
266 {
267 #ifdef PEGASUS_OS_TYPE_WINDOWS
268 _socketInterfaceRefCount--;
269
270 if (_socketInterfaceRefCount == 0)
|
271 david.dillard 1.20 WSACleanup();
|
272 mike 1.2 #endif
273 }
274
|
275 thilo.boehm 1.25 //------------------------------------------------------------------------------
276 //
277 // _setTCPNoDelay()
278 //
279 //------------------------------------------------------------------------------
280
281 inline void _setTCPNoDelay(SocketHandle socket)
282 {
283 // This function disables "Nagle's Algorithm" also known as "the TCP delay
284 // algorithm", which causes read operations to obtain whatever data is
|
285 kumpf 1.26 // already in the input queue and then wait a little longer to see if
286 // more data arrives. This algorithm optimizes the case in which data is
287 // sent in only one direction but severely impairs performance of round
288 // trip servers. Disabling TCP delay is a standard technique for round
|
289 thilo.boehm 1.25 // trip servers.
290
291 int opt = 1;
292 setsockopt(socket, IPPROTO_TCP, TCP_NODELAY, (char*)&opt, sizeof(opt));
293 }
294 //------------------------------------------------------------------------------
295 //
296 // _setInformIfNewTCPIP()
297 //
298 //------------------------------------------------------------------------------
299 inline void _setInformIfNewTCPIP(SocketHandle socket)
300 {
301 #ifdef PEGASUS_OS_ZOS
302 // This function enables the notification of the CIM Server that a new
|
303 kumpf 1.26 // TCPIP transport layer is active. This is needed to be aware of a
|
304 thilo.boehm 1.25 // restart of the transport layer. When this option is in effect,
305 // the accetp(), select(), and read() request will receive an errno=EIO.
306 // Once this happens, the socket should be closed and create a new.
|
307 kumpf 1.26
|
308 thilo.boehm 1.25 int NewTcpipOn = 1;
|
309 kumpf 1.26 setibmsockopt(
310 socket,
311 SOL_SOCKET,
312 SO_EioIfNewTP,
313 (char*)&NewTcpipOn,
314 sizeof(NewTcpipOn));
|
315 thilo.boehm 1.25 #endif
316 }
317
318
319 SocketHandle Socket::createSocket(int domain, int type, int protocol)
320 {
321 SocketHandle newSocket;
322
|
323 kumpf 1.26 if (domain == AF_UNIX)
|
324 thilo.boehm 1.25 {
|
325 kumpf 1.26 return socket(domain,type,protocol);
|
326 thilo.boehm 1.25 }
327
328 bool sendTcpipMsg = true;
329
|
330 kumpf 1.26 while (1)
|
331 thilo.boehm 1.25 {
332 newSocket = socket(domain,type,protocol);
333
|
334 kumpf 1.27 if ((newSocket != PEGASUS_INVALID_SOCKET) ||
335 (getSocketError() != PEGASUS_NETWORK_TRYAGAIN))
336 {
337 break;
338 }
339
340 #ifdef PEGASUS_OS_ZOS
|
341 thilo.boehm 1.25 // The program should wait for transport layer to become ready.
342
|
343 kumpf 1.27 if (sendTcpipMsg)
|
344 thilo.boehm 1.25 {
|
345 kumpf 1.27 Logger::put_l(
346 Logger::STANDARD_LOG, System::CIMSERVER, Logger::INFORMATION,
347 "Common.Socket.WAIT_FOR_TCPIP",
348 "TCP/IP temporary unavailable.");
349 sendTcpipMsg = false;
350 }
|
351 thilo.boehm 1.25
|
352 kumpf 1.27 System::sleep(30);
353 #endif
|
354 thilo.boehm 1.25 } // wait for the transport layer become ready.
355
356 // Is the socket in an unrecoverable error ?
357 if (newSocket == PEGASUS_INVALID_SOCKET)
358 {
359 // return immediate
|
360 kumpf 1.26 return PEGASUS_INVALID_SOCKET;
361 }
362 else
363 {
|
364 thilo.boehm 1.25 // set aditional socket options
365 _setTCPNoDelay(newSocket);
366 _setInformIfNewTCPIP(newSocket);
367
|
368 kumpf 1.26 return newSocket;
|
369 thilo.boehm 1.25 }
370 }
371
|
372 mike 1.2 PEGASUS_NAMESPACE_END
|