socket.hxx

Go to the documentation of this file.
00001 // Copyright (C) 2003-2006 Laboratoire de Recherche en Informatique
00002 
00003 // This file is part of Qolyester.
00004 
00005 // Qolyester is free software; you can redistribute it and/or
00006 // modify it under the terms of the GNU General Public License
00007 // as published by the Free Software Foundation; either version 2
00008 // of the License, or (at your option) any later version.
00009 
00010 // Qolyester is distributed in the hope that it will be useful,
00011 // but WITHOUT ANY WARRANTY; without even the implied warranty of
00012 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00013 // GNU General Public License for more details.
00014 
00015 // You should have received a copy of the GNU General Public License
00016 // along with this program; if not, write to the Free Software
00017 // Foundation, Inc., 51 Franklin Street, Fifth Floor,
00018 // Boston, MA  02110-1301, USA.
00019 
00020 #include "config.hh"
00021 
00022 #ifndef QOLYESTER_ENABLE_VIRTUAL
00023 
00024 # ifndef QOLYESTER_DAEMON_SYS_SOCKET_HXX
00025 #  define QOLYESTER_DAEMON_SYS_SOCKET_HXX 1
00026 
00027 #  include <sys/socket.h>
00028 #  include <fcntl.h>
00029 #  include <sys/ioctl.h>
00030 #  include <net/if.h>
00031 #  include <netinet/ip.h>
00032 #  include <sstream>
00033 
00034 #  include "cst/constants.hh"
00035 #  include "utl/exception.hh"
00036 
00037 #  include "sys/realinterfaceinfo.hh"
00038 
00039 #  include "socket.hh"
00040 
00041 namespace olsr {
00042 
00043 #  if QOLYESTER_FAMILY_INET == 6
00044   extern bool   dirty_promisc_hack;
00045 #  endif
00046 
00047   namespace sys {
00048 
00049     Socket::Socket(_dummy_values)
00050       : _fd(-1),
00051         _mtu(0),
00052         _baddr(),
00053         _index(0)
00054     {}
00055 
00056     Socket::Socket()
00057       : _mtu(0),
00058         _baddr(),
00059         _index(0) {
00060       init();
00061     }
00062 
00063     Socket::Socket(unsigned mtu)
00064       : _mtu(mtu),
00065         _baddr(),
00066         _index(0) {
00067       init();
00068     }
00069 
00070     Socket::Socket(unsigned mtu, const addr_t& addr, port_t port)
00071       : _mtu(mtu),
00072         _baddr(),
00073         _index(0) {
00074       init();
00075       bind(addr, port);
00076     }
00077 
00078     Socket::Socket(unsigned mtu, const std::string& host, port_t port)
00079       : _mtu(mtu),
00080         _baddr(),
00081         _index(0) {
00082       init();
00083       bind(addr_t(host), port);
00084     }
00085 
00086     Socket::Socket(unsigned mtu, const char* host, port_t port)
00087       : _mtu(mtu),
00088         _baddr(),
00089         _index(0) {
00090       init();
00091       bind(addr_t(std::string(host)), port);
00092     }
00093 
00094     void
00095     Socket::close() {
00096       if (_fd >= 0)
00097 	::close(_fd);
00098       _fd = -1;
00099     }
00100 
00101     void
00102     Socket::bind_to_device(const std::string& name) {
00103       if (::setsockopt(_fd, SOL_SOCKET, SO_BINDTODEVICE,
00104                        name.c_str(), name.length() + 1) < 0)
00105         throw errnoexcept_t(std::string("setsockopt(SO_BINDTODEVICE): ") +
00106                             strerror(errno), errno);
00107     }
00108 
00109     void
00110 #  if QOLYESTER_FAMILY_INET != 6
00111     Socket::set_multicast(const RealInterfaceInfo&) {
00112       int val = 1;
00113       if (setsockopt(_fd, SOL_SOCKET, SO_BROADCAST, &val, sizeof val) < 0)
00114         throw errnoexcept_t(std::string("setsockopt(SO_BROADCAST): ") +
00115                                         strerror(errno), errno);
00116 #  else // QOLYESTER_FAMILY_INET == 6
00117     Socket::set_multicast(const RealInterfaceInfo& info) {
00118       unsigned  index = info.index();
00119 
00120       if (setsockopt(_fd, IPPROTO_IPV6, IPV6_MULTICAST_IF,
00121                      &index, sizeof index) < 0)
00122         throw errnoexcept_t(std::string("setsockopt(IPV6_MULTICAST_IF): ") +
00123                             strerror(errno), errno);
00124       int       val = 0;
00125 
00126       if (setsockopt(_fd, IPPROTO_IPV6, IPV6_MULTICAST_LOOP,
00127                      &val, sizeof val) < 0)
00128         throw errnoexcept_t(std::string("setsockopt(IPV6_MULTICAST_LOOP): ") +
00129                                         strerror(errno), errno);
00130 
00131       if (dirty_promisc_hack) {
00132         ifreq   ifr;
00133         strncpy(ifr.ifr_name, info.name().c_str(), IFNAMSIZ);
00134         ifr.ifr_name[IFNAMSIZ - 1] = 0;
00135         if (ioctl(_fd, SIOCGIFFLAGS, &ifr) < 0)
00136           throw errnoexcept_t(std::string("ioctl(SIOCGIFFLAGS): ") +
00137                               strerror(errno), errno);
00138         if ((ifr.ifr_flags & IFF_PROMISC) == 0) {
00139           ifr.ifr_flags |= IFF_PROMISC;
00140           if (ioctl(_fd, SIOCSIFFLAGS, &ifr) < 0)
00141             throw errnoexcept_t(std::string("ioctl(SIOCSIFFLAGS): ") +
00142                                 strerror(errno), errno);
00143           ifr.ifr_flags &= ~IFF_PROMISC;
00144           if (ioctl(_fd, SIOCSIFFLAGS, &ifr) < 0)
00145             throw errnoexcept_t(std::string("ioctl(SIOCSIFFLAGS): ") +
00146                                 strerror(errno), errno);
00147         }
00148       }
00149 #  endif
00150     }
00151 
00152     void
00153     Socket::set_priority() {
00154 # if QOLYESTER_FAMILY_INET == 4
00155       char      tos = IPTOS_LOWDELAY;
00156       if (setsockopt(_fd, SOL_IP, IP_TOS, &tos, sizeof tos) < 0) {
00157         std::ostringstream      os;
00158 
00159         os << "setsockopt(SOL_IP, IP_TOS, " << tos << "): " << strerror(errno);
00160 
00161         throw errnoexcept_t(os.str(), errno);
00162       }
00163 # endif
00164     }
00165 
00166     void
00167     Socket::bind(const sockaddr_t& sin) {
00168       if (::bind(_fd, (::sockaddr*) &sin, sizeof sin) < 0) {
00169         std::stringstream       msg;
00170         msg << "bind("
00171             << address_t(sin) << ':' <<
00172 #  if QOLYESTER_FAMILY_INET == 6
00173           ntohs(sin.sin6_port)
00174 #  else // QOLYESTER_FAMILY_INET != 6
00175           ntohs(sin.sin_port)
00176 #  endif
00177             << "): "
00178             << strerror(errno);
00179         throw errnoexcept_t(msg.str(), errno);
00180       }
00181     }
00182 
00183     void
00184     Socket::bind_multicast(const RealInterfaceInfo& info,
00185                            const address_t& a, port_t port) {
00186 #  if QOLYESTER_FAMILY_INET == 6
00187       bind_to_device(info.name());
00188       _index = info.index();
00189 
00190       bind(a, port);
00191 
00192       set_multicast(info);
00193 
00194       int       hops = 1;
00195 
00196       if (setsockopt(_fd, IPPROTO_IPV6, IPV6_MULTICAST_HOPS,
00197                      &hops, sizeof hops) < 0)
00198         throw errnoexcept_t(std::string("setsockopt(IPV6_MULTICAST_HOPS): ") +
00199                             strerror(errno), errno);
00200 
00201       ipv6_mreq mreq;
00202       a.dump(reinterpret_cast<u_int8_t*>(&mreq.ipv6mr_multiaddr));
00203       mreq.ipv6mr_interface = info.index();
00204 
00205       if (setsockopt(_fd, IPPROTO_IPV6, IPV6_ADD_MEMBERSHIP,
00206                      &mreq, sizeof mreq) < 0) {
00207         std::stringstream       msg;
00208         msg << "setsockopt(IPV6_ADD_MEMBERSHIP, "
00209             << a << ", " << info.index() << "): " << strerror(errno);
00210         throw errnoexcept_t(msg.str(), errno);
00211       }
00212 
00213       int       val = 0;
00214 
00215       if (setsockopt(_fd, IPPROTO_IPV6, IPV6_MULTICAST_LOOP,
00216                      &val, sizeof val) < 0)
00217         throw errnoexcept_t(std::string("setsockopt(IPV6_MULTICAST_LOOP): ") +
00218                                         strerror(errno), errno);
00219 
00220 #  else // QOLYESTER_FAMILY_INET != 6
00221 
00222       bind(a, port);
00223       bind_to_device(info.name());
00224       set_multicast(info);
00225 
00226 #  endif
00227     }
00228 
00229 #  if QOLYESTER_FAMILY_INET == 6
00230     void
00231     Socket::bind(const addr_t& addr, port_t port, unsigned index) {
00232       sockaddr_t        sin = addr.make_sockaddr(port);
00233       sin.sin6_scope_id = index;
00234       bind(sin);
00235 #  else // QOLYESTER_FAMILY_INET != 6
00236     void
00237     Socket::bind(const addr_t& addr, port_t port) {
00238       bind(addr.make_sockaddr(port));
00239 #  endif
00240     }
00241 
00242     void
00243     Socket::connect(const sockaddr_t& sin) {
00244       if (::connect(_fd, (::sockaddr*) &sin, sizeof sin) < 0) {
00245         std::stringstream       msg;
00246         msg << "connect("
00247             << address_t(sin) << ':' <<
00248 #  if QOLYESTER_FAMILY_INET == 6
00249           ntohs(sin.sin6_port)
00250 #  else // QOLYESTER_FAMILY_INET != 6
00251           ntohs(sin.sin_port)
00252 #  endif
00253             << "): "
00254             << strerror(errno);
00255         throw errnoexcept_t(msg.str(), errno);
00256       }
00257     }
00258 
00259     void
00260     Socket::connect(const addr_t& addr, port_t port) {
00261       connect(addr.make_sockaddr(port));
00262     }
00263 
00264     utl::Data
00265     Socket::receive(address_t& sender) const {
00266       sockaddr_t        sin_from;
00267       socklen_t         sin_len = sizeof sin_from;
00268       utl::Data         data(_mtu);
00269       int               len;
00270       while ((len = ::recvfrom(_fd, data.raw(), data.size(), 0,
00271                                (sockaddr*) &sin_from, &sin_len)) < 0 &&
00272              errno == EINTR);
00273       if (len < 0)
00274         throw errnoexcept_t(std::string("recvfrom(): ") + strerror(errno),
00275                             errno);
00276 
00277       sender = address_t(sin_from);
00278 
00279       return data.shrink_to(len);
00280     }
00281 
00282     void
00283     Socket::send(const utl::ConstData& d) const {
00284       int       len;
00285       while ((len = ::send(_fd, d.raw(), d.size(), 0)) < 0 &&
00286              errno == EINTR);
00287       if (len < 0)
00288         throw errnoexcept_t(std::string("send(): ") + strerror(errno), errno);
00289     }
00290 
00291     void
00292     Socket::sendto(const utl::ConstData& d,
00293                    const address_t::sockaddr_t& s) const {
00294       int       len;
00295       while ((len = ::sendto(_fd, d.raw(), d.size(), 0,
00296                              reinterpret_cast<const sockaddr*>(&s),
00297                              sizeof s)) < 0 && errno == EINTR);
00298       if (len < 0) {
00299         std::stringstream       msg;
00300         msg << "sendto("
00301             << address_t(s) << ':' <<
00302 #  if QOLYESTER_FAMILY_INET == 6
00303           ntohs(s.sin6_port)
00304 #  else // QOLYESTER_FAMILY_INET != 6
00305           ntohs(s.sin_port)
00306 #  endif
00307             << "): "
00308             << strerror(errno);
00309         throw errnoexcept_t(msg.str(), errno);
00310       }
00311     }
00312 
00313     void
00314     Socket::sendto_bcast(const utl::ConstData& d) const {
00315       address_t::sockaddr_t     sin = _baddr.make_sockaddr(OLSR_PORT_NUMBER);
00316 #  if QOLYESTER_FAMILY_INET == 6
00317       sin.sin6_scope_id = _index;
00318 #  endif // QOLYESTER_FAMILY_INET != 6
00319       int       len;
00320       while ((len = ::sendto(_fd, d.raw(), d.size(), 0,
00321                              reinterpret_cast<sockaddr*>(&sin),
00322                              sizeof (address_t::sockaddr_t))) < 0 &&
00323              errno == EINTR);
00324       if (len < 0) {
00325         std::stringstream       msg;
00326         msg << "sendto("
00327             << address_t(sin) << ':' <<
00328 #  if QOLYESTER_FAMILY_INET == 6
00329           ntohs(sin.sin6_port)
00330 #  else // QOLYESTER_FAMILY_INET != 6
00331           ntohs(sin.sin_port)
00332 #  endif
00333             << "): "
00334             << strerror(errno);
00335         throw errnoexcept_t(msg.str(), errno);
00336       }
00337     }
00338 
00339     bool
00340     Socket::operator<(const This& rhs) const { return _fd < rhs._fd; }
00341 
00342     sch::IOEvent::p_t
00343     Socket::read_p() const {
00344       return sch::IOEvent::p_t(_fd, POLLIN);
00345     }
00346 
00347     sch::IOEvent::p_t
00348     Socket::write_p() const {
00349       return sch::IOEvent::p_t(_fd, POLLOUT);
00350     }
00351 
00352     void
00353     Socket::init() {
00354       if ((_fd = ::socket(addr_t::proto, SOCK_DGRAM, IPPROTO_UDP)) < 0)
00355         throw errnoexcept_t(std::string("socket(SOCK_DGRAM, IPPROTO_UDP): ") +
00356                             strerror(errno), errno);
00357       if (::fcntl(_fd, F_SETFL, O_RDWR | O_NONBLOCK) < 0)
00358         throw errnoexcept_t(std::string("fcntl(F_SETFL, O_NONBLOCK): ") +
00359                             strerror(errno), errno);
00360     }
00361 
00362   } // namespace sys
00363 
00364 } // namespace olsr
00365 
00366 # endif // ! QOLYESTER_DAEMON_SYS_SOCKET_HXX
00367 
00368 #endif // ! QOLYESTER_ENABLE_VIRTUAL

Generated on Mon Sep 10 17:02:13 2007 for Qolyester daemon by  doxygen 1.5.1