/src/resiprocate/rutil/Socket.cxx
Line | Count | Source |
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 | | |
15 | | using namespace resip; |
16 | | using namespace std; |
17 | | |
18 | | #define RESIPROCATE_SUBSYSTEM Subsystem::TRANSPORT |
19 | | |
20 | | bool |
21 | | resip::makeSocketNonBlocking(Socket fd) |
22 | 0 | { |
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 | 0 | int flags = fcntl( fd, F_GETFL, 0); |
32 | 0 | int errNoBlock = fcntl(fd, F_SETFL, flags | O_NONBLOCK ); |
33 | 0 | if ( errNoBlock != 0 ) // !cj! I may have messed up this line |
34 | 0 | { |
35 | 0 | return false; |
36 | 0 | } |
37 | 0 | #endif |
38 | 0 | return true; |
39 | 0 | } |
40 | | |
41 | | |
42 | | bool |
43 | | resip::makeSocketBlocking(Socket fd) |
44 | 0 | { |
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 | 0 | int flags = fcntl( fd, F_GETFL, 0); |
54 | 0 | int errNoBlock = fcntl(fd, F_SETFL, flags & ~O_NONBLOCK ); |
55 | 0 | if ( errNoBlock != 0 ) // !cj! I may have messed up this line |
56 | 0 | { |
57 | 0 | return false; |
58 | 0 | } |
59 | 0 | #endif |
60 | 0 | return true; |
61 | 0 | } |
62 | | |
63 | | |
64 | | |
65 | | bool |
66 | | resip::configureConnectedSocket(Socket fd) |
67 | 0 | { |
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 | 0 | return true; |
78 | 0 | } |
79 | | |
80 | | |
81 | | |
82 | | void |
83 | | resip::initNetwork() |
84 | 0 | { |
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 | 0 | } |
124 | | |
125 | | |
126 | | #if defined(WIN32) |
127 | | int |
128 | | resip::closeSocket( Socket fd ) |
129 | | { |
130 | | return closesocket(fd); |
131 | | } |
132 | | #else |
133 | | int |
134 | | resip::closeSocket( Socket fd ) |
135 | 0 | { |
136 | | //int ret = ::shutdown(fd, SHUT_RDWR); !jf! |
137 | 0 | int ret = ::close(fd); |
138 | 0 | if (ret < 0) |
139 | 0 | { |
140 | 0 | InfoLog (<< "Failed to shutdown socket " << fd << " : " << strerror(errno)); |
141 | 0 | } |
142 | 0 | return ret; |
143 | 0 | } |
144 | | #endif |
145 | | |
146 | | // code moved from resip/stack/ConnectionManager.cxx |
147 | | // appears to work on both linux and windows |
148 | | int resip::getSocketError(Socket fd) |
149 | 0 | { |
150 | 0 | int errNum = 0; |
151 | 0 | int errNumSize = sizeof(errNum); |
152 | 0 | getsockopt(fd, SOL_SOCKET, SO_ERROR, (char *)&errNum, (socklen_t *)&errNumSize); |
153 | | /// XXX: should check return code of getsockopt |
154 | 0 | return errNum; |
155 | 0 | } |
156 | | |
157 | | /** |
158 | | Returns negative on error, or number of (positive) allowed fds |
159 | | **/ |
160 | | int |
161 | | resip::increaseLimitFds(unsigned int targetFds) |
162 | 0 | { |
163 | | #if defined(WIN32) |
164 | | // kw: i don't know if any equiv on windows |
165 | | return targetFds; |
166 | | #else |
167 | 0 | struct rlimit lim; |
168 | |
|
169 | 0 | if (getrlimit(RLIMIT_NOFILE, &lim) < 0) |
170 | 0 | { |
171 | 0 | CritLog(<<"getrlimit(NOFILE) failed: " << strerror(errno)); |
172 | 0 | return -1; |
173 | 0 | } |
174 | 0 | if (lim.rlim_cur==RLIM_INFINITY || targetFds < lim.rlim_cur) |
175 | 0 | { |
176 | 0 | return targetFds; |
177 | 0 | } |
178 | | |
179 | 0 | int euid = geteuid(); |
180 | 0 | if (lim.rlim_max==RLIM_INFINITY || targetFds < lim.rlim_max) |
181 | 0 | { |
182 | 0 | lim.rlim_cur=targetFds; |
183 | 0 | } |
184 | 0 | else |
185 | 0 | { |
186 | 0 | if (euid!=0) |
187 | 0 | { |
188 | 0 | CritLog(<<"Attempting to increase number of fds when not root. This probably wont work"); |
189 | 0 | } |
190 | 0 | lim.rlim_cur=targetFds; |
191 | 0 | lim.rlim_max=targetFds; |
192 | 0 | } |
193 | |
|
194 | 0 | if (setrlimit(RLIMIT_NOFILE, &lim) < 0) |
195 | 0 | { |
196 | 0 | CritLog(<<"setrlimit(NOFILE)=(c="<<lim.rlim_cur<<",m="<<lim.rlim_max |
197 | 0 | <<",uid="<<euid<<") failed: " << strerror(errno)); |
198 | | /* There is intermediate: could raise cur to max */ |
199 | 0 | return -1; |
200 | 0 | } |
201 | 0 | return targetFds; |
202 | 0 | #endif |
203 | 0 | } |
204 | | |
205 | | /** |
206 | | Some OSs (Linux in particular) silently ignore requests to set |
207 | | too big and do not return an error code. Thus we always check. |
208 | | Also, the returned value (getsockopt) can be larger than the requested |
209 | | value (kernel internally doubles). |
210 | | manpage says sockopt uses integer as data-type |
211 | | If {buflen} is negative, we skip the set and just read |
212 | | Return the get size or -1 if the set didn't work |
213 | | **/ |
214 | | static int trySetRcvBuf(Socket fd, int buflen) |
215 | 0 | { |
216 | 0 | if (buflen > 0) |
217 | 0 | { |
218 | 0 | int wbuflen = buflen; |
219 | 0 | #if !defined(WIN32) |
220 | 0 | 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 | 0 | { |
225 | 0 | return -1; |
226 | 0 | } |
227 | 0 | } |
228 | 0 | int rbuflen = 0; |
229 | 0 | unsigned optlen = sizeof(rbuflen); |
230 | 0 | if (getsockopt(fd, SOL_SOCKET, SO_RCVBUF, (char *)&rbuflen, (socklen_t *)&optlen) == -1) |
231 | 0 | { |
232 | 0 | return -1; |
233 | 0 | } |
234 | 0 | resip_assert(optlen == sizeof(rbuflen)); |
235 | 0 | if (rbuflen < buflen) |
236 | 0 | { |
237 | 0 | return -1; |
238 | 0 | } |
239 | 0 | return rbuflen; |
240 | 0 | } |
241 | | |
242 | | /** |
243 | | **/ |
244 | | int resip::setSocketRcvBufLen(Socket fd, int buflen) |
245 | 0 | { |
246 | 0 | resip_assert(buflen >= 1024); |
247 | 0 | int goal=buflen; |
248 | 0 | int trylen=goal; |
249 | 0 | int sts; |
250 | 0 | int lastgoodset = 0, lastgoodget=0; |
251 | | |
252 | | /* go down by factors of 2 */ |
253 | 0 | for (; ; trylen /= 2) |
254 | 0 | { |
255 | 0 | if (trylen < 1024) |
256 | 0 | { |
257 | 0 | ErrLog(<<"setsockopt(SO_RCVBUF) failed"); |
258 | 0 | return -1; |
259 | 0 | } |
260 | 0 | if ((sts=trySetRcvBuf(fd, trylen)) >= 0) |
261 | 0 | { |
262 | 0 | lastgoodset = trylen; |
263 | 0 | lastgoodget = sts; |
264 | 0 | break; |
265 | 0 | } |
266 | 0 | } |
267 | | |
268 | | /* go up by 10% steps */ |
269 | 0 | unsigned step = trylen/10; |
270 | 0 | for ( ; trylen<goal; trylen+=step) |
271 | 0 | { |
272 | 0 | if ((sts=trySetRcvBuf(fd,trylen)) < 0) |
273 | 0 | { |
274 | 0 | break; |
275 | 0 | } |
276 | 0 | lastgoodset = trylen; |
277 | 0 | lastgoodget = sts; |
278 | 0 | } |
279 | 0 | if (lastgoodset < goal) |
280 | 0 | { |
281 | 0 | ErrLog(<<"setsockopt(SO_RCVBUF) goal "<<goal<<" not met (set=" |
282 | 0 | <<lastgoodset<<",get="<<lastgoodget<<")"); |
283 | 0 | } |
284 | 0 | else |
285 | 0 | { |
286 | 0 | InfoLog(<<"setsockopt(SO_RCVBUF) goal "<<goal<<" met (set=" |
287 | 0 | <<lastgoodset<<",get="<<lastgoodget<<")"); |
288 | 0 | } |
289 | 0 | return lastgoodset; |
290 | 0 | } |
291 | | |
292 | | |
293 | | /* ==================================================================== |
294 | | * The Vovida Software License, Version 1.0 |
295 | | * |
296 | | * Copyright (c) 2000 Vovida Networks, Inc. All rights reserved. |
297 | | * |
298 | | * Redistribution and use in source and binary forms, with or without |
299 | | * modification, are permitted provided that the following conditions |
300 | | * are met: |
301 | | * |
302 | | * 1. Redistributions of source code must retain the above copyright |
303 | | * notice, this list of conditions and the following disclaimer. |
304 | | * |
305 | | * 2. Redistributions in binary form must reproduce the above copyright |
306 | | * notice, this list of conditions and the following disclaimer in |
307 | | * the documentation and/or other materials provided with the |
308 | | * distribution. |
309 | | * |
310 | | * 3. The names "VOCAL", "Vovida Open Communication Application Library", |
311 | | * and "Vovida Open Communication Application Library (VOCAL)" must |
312 | | * not be used to endorse or promote products derived from this |
313 | | * software without prior written permission. For written |
314 | | * permission, please contact vocal@vovida.org. |
315 | | * |
316 | | * 4. Products derived from this software may not be called "VOCAL", nor |
317 | | * may "VOCAL" appear in their name, without prior written |
318 | | * permission of Vovida Networks, Inc. |
319 | | * |
320 | | * THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESSED OR IMPLIED |
321 | | * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES |
322 | | * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, TITLE AND |
323 | | * NON-INFRINGEMENT ARE DISCLAIMED. IN NO EVENT SHALL VOVIDA |
324 | | * NETWORKS, INC. OR ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT DAMAGES |
325 | | * IN EXCESS OF $1,000, NOR FOR ANY INDIRECT, INCIDENTAL, SPECIAL, |
326 | | * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, |
327 | | * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR |
328 | | * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY |
329 | | * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT |
330 | | * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE |
331 | | * USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH |
332 | | * DAMAGE. |
333 | | * |
334 | | * ==================================================================== |
335 | | * |
336 | | * This software consists of voluntary contributions made by Vovida |
337 | | * Networks, Inc. and many individuals on behalf of Vovida Networks, |
338 | | * Inc. For more information on Vovida Networks, Inc., please see |
339 | | * <http://www.vovida.org/>. |
340 | | * |
341 | | */ |