reSIProcate/rutil  9694
Socket.cxx
Go to the documentation of this file.
00001 
00002 #include <cassert>
00003 #include <fcntl.h>
00004 #include <errno.h>
00005 
00006 #include "rutil/compat.hxx"
00007 #include "rutil/Socket.hxx"
00008 #include "rutil/Logger.hxx"
00009 
00010 #ifndef WIN32
00011 #include <unistd.h>
00012 #include <sys/resource.h>       // for getrlimit()
00013 #endif
00014 
00015 using namespace resip;
00016 using namespace std;
00017 
00018 #define RESIPROCATE_SUBSYSTEM Subsystem::TRANSPORT
00019 
00020 bool
00021 resip::makeSocketNonBlocking(Socket fd)
00022 {
00023 #if defined(WIN32)
00024         unsigned long noBlock = 1;
00025         int errNoBlock = ioctlsocket( fd, FIONBIO , &noBlock );
00026         if ( errNoBlock != 0 )
00027         {
00028                 return false;
00029         }
00030 #else
00031         int flags  = fcntl( fd, F_GETFL, 0);
00032         int errNoBlock = fcntl(fd, F_SETFL, flags | O_NONBLOCK );
00033         if ( errNoBlock != 0 ) // !cj! I may have messed up this line
00034         {
00035                 return false;
00036         }
00037 #endif
00038         return true;
00039 }
00040 
00041 
00042 bool
00043 resip::makeSocketBlocking(Socket fd)
00044 {
00045 #if defined(WIN32)
00046         unsigned long noBlock = 0;
00047         int errNoBlock = ioctlsocket( fd, FIONBIO , &noBlock );
00048         if ( errNoBlock != 0 )
00049         {
00050                 return false;
00051         }
00052 #else
00053         int flags  = fcntl( fd, F_GETFL, 0);
00054         int errNoBlock = fcntl(fd, F_SETFL, flags & ~O_NONBLOCK );
00055         if ( errNoBlock != 0 ) // !cj! I may have messed up this line
00056         {
00057                 return false;
00058         }
00059 #endif
00060         return true;
00061 }
00062 
00063 
00064 
00065 void
00066 resip::initNetwork()
00067 {
00068 #if defined(WIN32)
00069         bool doneInit=false;
00070         if( !doneInit )
00071         {
00072                 doneInit=true;
00073 
00074    WORD wVersionRequested = MAKEWORD( 2, 2 );
00075    WSADATA wsaData;
00076    int err;
00077 
00078    err = WSAStartup( wVersionRequested, &wsaData );
00079    if ( err != 0 )
00080    {
00081       // could not find a usable WinSock DLL
00082       //cerr << "Could not load winsock" << endl;
00083       assert(0); // is this is failing, try a different version that 2.2, 1.0 or later will likely work
00084       exit(1);
00085    }
00086 
00087    /* Confirm that the WinSock DLL supports 2.2.*/
00088    /* Note that if the DLL supports versions greater    */
00089    /* than 2.2 in addition to 2.2, it will still return */
00090    /* 2.2 in wVersion since that is the version we      */
00091    /* requested.                                        */
00092 
00093    if ( LOBYTE( wsaData.wVersion ) != 2 ||
00094         HIBYTE( wsaData.wVersion ) != 2 )
00095    {
00096       /* Tell the user that we could not find a usable */
00097       /* WinSock DLL.                                  */
00098       WSACleanup( );
00099       //cerr << "Bad winsock verion" << endl;
00100       // TODO !cj! - add error message logging
00101       assert(0); // if this is failing, try a different version that 2.2, 1.0 or later will likely work
00102       exit(1);
00103    }
00104         }
00105 #endif
00106 }
00107 
00108 
00109 #if defined(WIN32)
00110 int
00111 resip::closeSocket( Socket fd )
00112 {
00113    return closesocket(fd);
00114 }
00115 #else
00116 int
00117 resip::closeSocket( Socket fd )
00118 {
00119    //int ret = ::shutdown(fd, SHUT_RDWR); !jf!
00120    int ret = ::close(fd);
00121    if (ret < 0)
00122    {
00123       InfoLog (<< "Failed to shutdown socket " << fd << " : " << strerror(errno));
00124    }
00125    return ret;
00126 }
00127 #endif
00128 
00129 // code moved from resip/stack/ConnectionManager.cxx
00130 // appears to work on both linux and windows
00131 int resip::getSocketError(Socket fd)
00132 {
00133    int errNum = 0;
00134    int errNumSize = sizeof(errNum);
00135    getsockopt(fd, SOL_SOCKET, SO_ERROR,
00136      (char *)&errNum, (socklen_t *)&errNumSize);
00138    return errNum;
00139 }
00140 
00144 int
00145 resip::increaseLimitFds(unsigned int targetFds)
00146 {
00147 #if defined(WIN32)
00148     // kw: i don't know if any equiv on windows
00149     return targetFds;
00150 #else
00151     struct rlimit lim;
00152 
00153     if (getrlimit(RLIMIT_NOFILE, &lim) < 0)
00154         {
00155            CritLog(<<"getrlimit(NOFILE) failed: " << strerror(errno));
00156            return -1;
00157     }
00158     if (lim.rlim_cur==RLIM_INFINITY || targetFds < lim.rlim_cur)
00159         {
00160         return targetFds;
00161         }
00162 
00163     int euid = geteuid();
00164     if (lim.rlim_max==RLIM_INFINITY || targetFds < lim.rlim_max)
00165         {
00166         lim.rlim_cur=targetFds;
00167     }
00168         else
00169         {
00170            if (euid!=0)
00171            {
00172               CritLog(<<"Attempting to increase number of fds when not root. This probably wont work");
00173            }
00174        lim.rlim_cur=targetFds;
00175        lim.rlim_max=targetFds;
00176     }
00177 
00178     if (setrlimit(RLIMIT_NOFILE, &lim) < 0)
00179         {
00180            CritLog(<<"setrlimit(NOFILE)=(c="<<lim.rlim_cur<<",m="<<lim.rlim_max
00181               <<",uid="<<euid<<") failed: " << strerror(errno));
00182            /* There is intermediate: could raise cur to max */
00183            return -1;
00184     }
00185     return targetFds;
00186 #endif
00187 }
00188 
00198 static int trySetRcvBuf(Socket fd, int buflen)
00199 {
00200    if (buflen > 0)
00201    {
00202       int wbuflen = buflen;
00203 #if !defined(WIN32)
00204       if (::setsockopt (fd, SOL_SOCKET, SO_RCVBUF, &wbuflen, sizeof(wbuflen)) == -1)
00205 #else
00206       if (::setsockopt (fd, SOL_SOCKET, SO_RCVBUF, (const char*)&wbuflen, sizeof(wbuflen)) == -1)
00207 #endif
00208       {
00209          return -1;
00210       }
00211    }
00212    int rbuflen = 0;
00213    unsigned optlen = sizeof(rbuflen);
00214    if (getsockopt(fd, SOL_SOCKET, SO_RCVBUF, (char *)&rbuflen, (socklen_t *)&optlen) == -1)
00215    {
00216       return -1;
00217    }
00218    assert(optlen == sizeof(rbuflen));
00219    if (rbuflen < buflen)
00220    {
00221       return -1;
00222    }
00223    return rbuflen;
00224 }
00225 
00228 int resip::setSocketRcvBufLen(Socket fd, int buflen)
00229 {
00230    assert(buflen >= 1024);
00231    int goal=buflen;
00232    int trylen=goal;
00233    int sts;
00234    int lastgoodset = 0, lastgoodget=0;
00235 
00236    /* go down by factors of 2 */
00237    for (; ; trylen /= 2)
00238    {
00239       if (trylen < 1024)
00240       {
00241         ErrLog(<<"setsockopt(SO_RCVBUF) failed");
00242         return -1;
00243       }
00244       if ((sts=trySetRcvBuf(fd, trylen)) >= 0)
00245       {
00246          lastgoodset = trylen;
00247          lastgoodget = sts;
00248          break;
00249       }
00250    }
00251 
00252    /* go up by 10% steps */
00253    unsigned step = trylen/10;
00254    for ( ; trylen<goal; trylen+=step)
00255    {
00256       if ((sts=trySetRcvBuf(fd,trylen)) < 0)
00257       {
00258          break;
00259       }
00260       lastgoodset = trylen;
00261       lastgoodget = sts;
00262    }
00263    if (lastgoodset < goal)
00264    {
00265       ErrLog(<<"setsockopt(SO_RCVBUF) goal "<<goal<<" not met (set="
00266          <<lastgoodset<<",get="<<lastgoodget<<")");
00267    }
00268    else
00269    {
00270       InfoLog(<<"setsockopt(SO_RCVBUF) goal "<<goal<<" met (set="
00271          <<lastgoodset<<",get="<<lastgoodget<<")");
00272    }
00273    return lastgoodset;
00274 }
00275 
00276 
00277 /* ====================================================================
00278  * The Vovida Software License, Version 1.0
00279  *
00280  * Copyright (c) 2000 Vovida Networks, Inc.  All rights reserved.
00281  *
00282  * Redistribution and use in source and binary forms, with or without
00283  * modification, are permitted provided that the following conditions
00284  * are met:
00285  *
00286  * 1. Redistributions of source code must retain the above copyright
00287  *    notice, this list of conditions and the following disclaimer.
00288  *
00289  * 2. Redistributions in binary form must reproduce the above copyright
00290  *    notice, this list of conditions and the following disclaimer in
00291  *    the documentation and/or other materials provided with the
00292  *    distribution.
00293  *
00294  * 3. The names "VOCAL", "Vovida Open Communication Application Library",
00295  *    and "Vovida Open Communication Application Library (VOCAL)" must
00296  *    not be used to endorse or promote products derived from this
00297  *    software without prior written permission. For written
00298  *    permission, please contact vocal@vovida.org.
00299  *
00300  * 4. Products derived from this software may not be called "VOCAL", nor
00301  *    may "VOCAL" appear in their name, without prior written
00302  *    permission of Vovida Networks, Inc.
00303  *
00304  * THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESSED OR IMPLIED
00305  * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
00306  * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, TITLE AND
00307  * NON-INFRINGEMENT ARE DISCLAIMED.  IN NO EVENT SHALL VOVIDA
00308  * NETWORKS, INC. OR ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT DAMAGES
00309  * IN EXCESS OF $1,000, NOR FOR ANY INDIRECT, INCIDENTAL, SPECIAL,
00310  * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
00311  * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
00312  * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
00313  * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
00314  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE
00315  * USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH
00316  * DAMAGE.
00317  *
00318  * ====================================================================
00319  *
00320  * This software consists of voluntary contributions made by Vovida
00321  * Networks, Inc. and many individuals on behalf of Vovida Networks,
00322  * Inc.  For more information on Vovida Networks, Inc., please see
00323  * <http://www.vovida.org/>.
00324  *
00325  */