reSIProcate
SIP stack, Dialog Usage Manager and related libraries
Loading...
Searching...
No Matches
Socket.cxx
Go to the documentation of this file.
1
2#include "rutil/ResipAssert.h"
3#include <fcntl.h>
4#include <errno.h>
5
6#include "rutil/compat.hxx"
7#include "rutil/Socket.hxx"
8#include "rutil/Logger.hxx"
9
10#ifndef WIN32
11#include <unistd.h>
12#include <sys/resource.h> // for getrlimit()
13#endif
14
15using namespace resip;
16using namespace std;
17
18#define RESIPROCATE_SUBSYSTEM Subsystem::TRANSPORT
19
20bool
22{
23#if defined(WIN32)
24 unsigned long noBlock = 1;
25 int errNoBlock = ioctlsocket( fd, FIONBIO , &noBlock );
26 if ( errNoBlock != 0 )
27 {
28 return false;
29 }
30#else
31 int flags = fcntl( fd, F_GETFL, 0);
32 int errNoBlock = fcntl(fd, F_SETFL, flags | O_NONBLOCK );
33 if ( errNoBlock != 0 ) // !cj! I may have messed up this line
34 {
35 return false;
36 }
37#endif
38 return true;
39}
40
41
42bool
44{
45#if defined(WIN32)
46 unsigned long noBlock = 0;
47 int errNoBlock = ioctlsocket( fd, FIONBIO , &noBlock );
48 if ( errNoBlock != 0 )
49 {
50 return false;
51 }
52#else
53 int flags = fcntl( fd, F_GETFL, 0);
54 int errNoBlock = fcntl(fd, F_SETFL, flags & ~O_NONBLOCK );
55 if ( errNoBlock != 0 ) // !cj! I may have messed up this line
56 {
57 return false;
58 }
59#endif
60 return true;
61}
62
63
64
65bool
67{
68#ifdef REQUIRE_SO_NOSIGPIPE
69 int on = 1;
70 if ( ::setsockopt ( fd, SOL_SOCKET, SO_NOSIGPIPE, (const char*)&on, sizeof(on)) )
71 {
72 int e = getErrno();
73 ErrLog (<< "Couldn't set sockoption SO_NOSIGPIPE: " << strError(e));
74 return false;
75 }
76#endif
77 return true;
78}
79
80
81
82void
84{
85#if defined(WIN32)
86 bool doneInit=false;
87 if( !doneInit )
88 {
89 doneInit=true;
90
91 WORD wVersionRequested = MAKEWORD( 2, 2 );
92 WSADATA wsaData;
93 int err;
94
95 err = WSAStartup( wVersionRequested, &wsaData );
96 if ( err != 0 )
97 {
98 // could not find a usable WinSock DLL
99 //cerr << "Could not load winsock" << endl;
100 resip_assert(0); // is this is failing, try a different version that 2.2, 1.0 or later will likely work
101 exit(1);
102 }
103
104 /* Confirm that the WinSock DLL supports 2.2.*/
105 /* Note that if the DLL supports versions greater */
106 /* than 2.2 in addition to 2.2, it will still return */
107 /* 2.2 in wVersion since that is the version we */
108 /* requested. */
109
110 if ( LOBYTE( wsaData.wVersion ) != 2 ||
111 HIBYTE( wsaData.wVersion ) != 2 )
112 {
113 /* Tell the user that we could not find a usable */
114 /* WinSock DLL. */
115 WSACleanup( );
116 //cerr << "Bad winsock verion" << endl;
117 // TODO !cj! - add error message logging
118 resip_assert(0); // if this is failing, try a different version that 2.2, 1.0 or later will likely work
119 exit(1);
120 }
121 }
122#endif
123}
124
125
126#if defined(WIN32)
127int
129{
130 return closesocket(fd);
131}
132#else
133int
135{
136 //int ret = ::shutdown(fd, SHUT_RDWR); !jf!
137 int ret = ::close(fd);
138 if (ret < 0)
139 {
140 InfoLog (<< "Failed to shutdown socket " << fd << " : " << strError(errno));
141 }
142 return ret;
143}
144#endif
145
146// code moved from resip/stack/ConnectionManager.cxx
147// appears to work on both linux and windows
149{
150 int errNum = 0;
151 int errNumSize = sizeof(errNum);
152 getsockopt(fd, SOL_SOCKET, SO_ERROR, (char *)&errNum, (socklen_t *)&errNumSize);
154 return errNum;
155}
156
160int
161resip::increaseLimitFds(unsigned int targetFds)
162{
163#if defined(WIN32)
164 // kw: i don't know if any equiv on windows
165 return targetFds;
166#else
167 struct rlimit lim;
168
169 if (getrlimit(RLIMIT_NOFILE, &lim) < 0)
170 {
171 CritLog(<<"getrlimit(NOFILE) failed: " << strError(errno));
172 return -1;
173 }
174 if (lim.rlim_cur==RLIM_INFINITY || targetFds < lim.rlim_cur)
175 {
176 return targetFds;
177 }
178
179 int euid = geteuid();
180 if (lim.rlim_max==RLIM_INFINITY || targetFds < lim.rlim_max)
181 {
182 lim.rlim_cur=targetFds;
183 }
184 else
185 {
186 if (euid!=0)
187 {
188 CritLog(<<"Attempting to increase number of fds when not root. This probably wont work");
189 }
190 lim.rlim_cur=targetFds;
191 lim.rlim_max=targetFds;
192 }
193
194 if (setrlimit(RLIMIT_NOFILE, &lim) < 0)
195 {
196 CritLog(<<"setrlimit(NOFILE)=(c="<<lim.rlim_cur<<",m="<<lim.rlim_max
197 <<",uid="<<euid<<") failed: " << strError(errno));
198 /* There is intermediate: could raise cur to max */
199 return -1;
200 }
201 return targetFds;
202#endif
203}
204
214static int trySetRcvBuf(Socket fd, int buflen)
215{
216 if (buflen > 0)
217 {
218 int wbuflen = buflen;
219#if !defined(WIN32)
220 if (::setsockopt (fd, SOL_SOCKET, SO_RCVBUF, &wbuflen, sizeof(wbuflen)) == -1)
221#else
222 if (::setsockopt (fd, SOL_SOCKET, SO_RCVBUF, (const char*)&wbuflen, sizeof(wbuflen)) == -1)
223#endif
224 {
225 return -1;
226 }
227 }
228 int rbuflen = 0;
229 unsigned optlen = sizeof(rbuflen);
230 if (getsockopt(fd, SOL_SOCKET, SO_RCVBUF, (char *)&rbuflen, (socklen_t *)&optlen) == -1)
231 {
232 return -1;
233 }
234 resip_assert(optlen == sizeof(rbuflen));
235 if (rbuflen < buflen)
236 {
237 return -1;
238 }
239 return rbuflen;
240}
241
245{
246 resip_assert(buflen >= 1024);
247 int goal=buflen;
248 int trylen=goal;
249 int sts;
250 int lastgoodset = 0, lastgoodget=0;
251
252 /* go down by factors of 2 */
253 for (; ; trylen /= 2)
254 {
255 if (trylen < 1024)
256 {
257 ErrLog(<<"setsockopt(SO_RCVBUF) failed");
258 return -1;
259 }
260 if ((sts=trySetRcvBuf(fd, trylen)) >= 0)
261 {
262 lastgoodset = trylen;
263 lastgoodget = sts;
264 break;
265 }
266 }
267
268 /* go up by 10% steps */
269 unsigned step = trylen/10;
270 for ( ; trylen<goal; trylen+=step)
271 {
272 if ((sts=trySetRcvBuf(fd,trylen)) < 0)
273 {
274 break;
275 }
276 lastgoodset = trylen;
277 lastgoodget = sts;
278 }
279 if (lastgoodset < goal)
280 {
281 ErrLog(<<"setsockopt(SO_RCVBUF) goal "<<goal<<" not met (set="
282 <<lastgoodset<<",get="<<lastgoodget<<")");
283 }
284 else
285 {
286 InfoLog(<<"setsockopt(SO_RCVBUF) goal "<<goal<<" met (set="
287 <<lastgoodset<<",get="<<lastgoodget<<")");
288 }
289 return lastgoodset;
290}
291
292int resip::setSocketDscp(Socket fd, int dscp, IpVersion version)
293{
294 const bool isV6 = (version == V6);
295 const int level = isV6 ? IPPROTO_IPV6 : IPPROTO_IP;
296 const int option = isV6 ? IPV6_TCLASS : IP_TOS;
297 const char* optionName = isV6 ? "IPV6_TCLASS" : "IP_TOS";
298
299 // For a direct caller: the transport refuses the value first, so this
300 // cannot fire on the stack's own path.
301 if (dscp < 0 || dscp > 63)
302 {
303 ErrLog(<< "DSCP class " << dscp << " out of range 0..63 on fd " << fd);
304 return -1;
305 }
306
307 const int tos = dscp << 2;
308
309 if (::setsockopt(fd, level, option, (const char *)&tos, sizeof(tos)) == -1)
310 {
311 int e = getErrno();
312 // Below Debug: a refresh reaches every socket the transport holds, so
313 // this arrives in bursts. The caller reports the state once instead.
314 StackLog(<< "setsockopt(" << optionName << ", " << tos << ") failed on fd " << fd
315 << ": error " << e);
316 return -1;
317 }
318
319 return getSocketDscp(fd, version);
320}
321
323{
324 const bool isV6 = (version == V6);
325 const int level = isV6 ? IPPROTO_IPV6 : IPPROTO_IP;
326 const int option = isV6 ? IPV6_TCLASS : IP_TOS;
327
328 int tos = 0;
329 socklen_t optlen = sizeof(tos);
330 if (::getsockopt(fd, level, option, (char *)&tos, &optlen) == -1)
331 {
332 int e = getErrno();
333 // Below Debug, for the same reason as the write above.
334 StackLog(<< "getsockopt(" << (isV6 ? "IPV6_TCLASS" : "IP_TOS")
335 << ") failed on fd " << fd << ": error " << e);
336 return -1;
337 }
338
339 return tos;
340}
341
343{
344 const int tos = getSocketTos(fd, version);
345
346 return (tos < 0) ? -1 : (tos >> 2);
347}
348
349
350/* ====================================================================
351 * The Vovida Software License, Version 1.0
352 *
353 * Copyright (c) 2000 Vovida Networks, Inc. All rights reserved.
354 *
355 * Redistribution and use in source and binary forms, with or without
356 * modification, are permitted provided that the following conditions
357 * are met:
358 *
359 * 1. Redistributions of source code must retain the above copyright
360 * notice, this list of conditions and the following disclaimer.
361 *
362 * 2. Redistributions in binary form must reproduce the above copyright
363 * notice, this list of conditions and the following disclaimer in
364 * the documentation and/or other materials provided with the
365 * distribution.
366 *
367 * 3. The names "VOCAL", "Vovida Open Communication Application Library",
368 * and "Vovida Open Communication Application Library (VOCAL)" must
369 * not be used to endorse or promote products derived from this
370 * software without prior written permission. For written
371 * permission, please contact vocal@vovida.org.
372 *
373 * 4. Products derived from this software may not be called "VOCAL", nor
374 * may "VOCAL" appear in their name, without prior written
375 * permission of Vovida Networks, Inc.
376 *
377 * THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESSED OR IMPLIED
378 * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
379 * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, TITLE AND
380 * NON-INFRINGEMENT ARE DISCLAIMED. IN NO EVENT SHALL VOVIDA
381 * NETWORKS, INC. OR ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT DAMAGES
382 * IN EXCESS OF $1,000, NOR FOR ANY INDIRECT, INCIDENTAL, SPECIAL,
383 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
384 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
385 * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
386 * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
387 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE
388 * USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH
389 * DAMAGE.
390 *
391 * ====================================================================
392 *
393 * This software consists of voluntary contributions made by Vovida
394 * Networks, Inc. and many individuals on behalf of Vovida Networks,
395 * Inc. For more information on Vovida Networks, Inc., please see
396 * <http://www.vovida.org/>.
397 *
398 */
#define StackLog(args_)
Definition Logger.hxx:125
#define InfoLog(args_)
Definition Logger.hxx:131
#define CritLog(args_)
Definition Logger.hxx:140
#define ErrLog(args_)
Definition Logger.hxx:137
#define resip_assert(x)
This file needs to work for both C and C++ code.
static int trySetRcvBuf(Socket fd, int buflen)
Some OSs (Linux in particular) silently ignore requests to set too big and do not return an error cod...
Definition Socket.cxx:214
Handles cross-platform sockets compatibility.
static const struct nv flags[]
Definition adig.c:62
int Socket
This file is used to handle compatibility fixes/tweaks so reSIProcate can function on multiple platfo...
dcm! – add UnusedChecking(_enum) below;
bool makeSocketBlocking(Socket fd)
Definition Socket.cxx:43
int getSocketError(Socket fd)
Definition Socket.cxx:148
int getSocketDscp(Socket fd, IpVersion version)
The DSCP class of {fd}, which is getSocketTos() without the ECN bits.
Definition Socket.cxx:342
int increaseLimitFds(unsigned int targetFds)
Returns negative on error, or number of (positive) allowed fds.
Definition Socket.cxx:161
bool configureConnectedSocket(Socket fd)
Definition Socket.cxx:66
void initNetwork()
set up network - does nothing in unix but needed for windows
Definition Socket.cxx:83
int Socket
Definition Socket.hxx:94
int closeSocket(Socket fd)
Definition Socket.cxx:134
int setSocketDscp(Socket fd, int dscp, IpVersion version)
Sets the DSCP class of {fd}, in the IPv4 ToS byte or the IPv6 traffic class, and reads it back.
Definition Socket.cxx:292
int setSocketRcvBufLen(Socket fd, int buflen)
Definition Socket.cxx:244
int getErrno()
Definition Socket.hxx:97
std::string strError(int err)
Definition compat.hxx:274
int getSocketTos(Socket fd, IpVersion version)
Reads the IPv4 ToS byte, or the IPv6 traffic class, of {fd}.
Definition Socket.cxx:322
IpVersion
An enumeration of IP versions.
bool makeSocketNonBlocking(Socket fd)
Definition Socket.cxx:21