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